From bbbfa64b3736af8cf6be7fa495c04be0b1874606 Mon Sep 17 00:00:00 2001 From: twowater <347073565@qq.com> Date: Mon, 31 Jul 2017 00:44:51 +0800 Subject: [PATCH] =?UTF-8?q?Signed-off-by:=20twowater=20<347073565@qq.com>?= =?UTF-8?q?=20=E8=8D=89=E6=A0=B9=E5=AD=A6Python=EF=BC=88=E4=B9=9D=EF=BC=89?= =?UTF-8?q?=20=E9=9D=A2=E5=90=91=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- SUMMARY.md | 9 ++- python9/1.md | 32 +++++++++ python9/2.md | 118 +++++++++++++++++++++++++++++++ python9/3.md | 64 +++++++++++++++++ python9/4.md | 106 ++++++++++++++++++++++++++++ python9/5.md | 170 +++++++++++++++++++++++++++++++++++++++++++++ python9/6.md | 67 ++++++++++++++++++ python9/Preface.md | 10 +++ 9 files changed, 577 insertions(+), 2 deletions(-) create mode 100644 python9/1.md create mode 100644 python9/2.md create mode 100644 python9/3.md create mode 100644 python9/4.md create mode 100644 python9/5.md create mode 100644 python9/6.md create mode 100644 python9/Preface.md diff --git a/README.md b/README.md index d0820be..08da2b7 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,5 @@ |草根学Python(五) 条件语句和循环语句|[掘金](https://juejin.im/post/594c6c52f265da6c1f75f164),[简书](http://www.jianshu.com/p/2b80009b1e8c),[CSDN](http://blog.csdn.net/Two_Water/article/details/73762517),[个人博客](http://twowater.com.cn/2017/06/27/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E4%BA%94-%E6%9D%A1%E4%BB%B6%E8%AF%AD%E5%8F%A5%E5%92%8C%E5%BE%AA%E7%8E%AF%E8%AF%AD%E5%8F%A5/)| |草根学Python(六) 函数|[掘金](https://juejin.im/post/5946784461ff4b006cf1d8ec),[简书](http://www.jianshu.com/p/d8f2a55edc75),[CSDN](http://blog.csdn.net/Two_Water/article/details/73865622),[个人博客](http://twowater.com.cn/2017/06/29/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E5%85%AD-%E5%87%BD%E6%95%B0/)| |草根学Python(七) 迭代器和生成器|[掘金](https://juejin.im/post/59589fedf265da6c386ce4ac),[简书](http://www.jianshu.com/p/74c0c1db1490),[CSDN](http://blog.csdn.net/Two_Water/article/details/74164652),[个人博客](http://twowater.com.cn/2017/07/02/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E4%B8%83-%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%92%8C%E7%94%9F%E6%88%90%E5%99%A8/)| -|草根学Python(八) 模块与包|[掘金](https://juejin.im/post/5962ddf95188252ec34009da),[简书](http://www.jianshu.com/p/7f05f915d2ac),[CSDN](http://blog.csdn.net/Two_Water/article/details/75042211),[个人博客](http://twowater.com.cn/2017/07/12/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E5%85%AB-%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%8C%85/)| \ No newline at end of file +|草根学Python(八) 模块与包|[掘金](https://juejin.im/post/5962ddf95188252ec34009da),[简书](http://www.jianshu.com/p/7f05f915d2ac),[CSDN](http://blog.csdn.net/Two_Water/article/details/75042211),[个人博客](http://twowater.com.cn/2017/07/12/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E5%85%AB-%E6%A8%A1%E5%9D%97%E4%B8%8E%E5%8C%85/)| +|草根学Python(九) 面向对象|[掘金](https://juejin.im/post/596ca6656fb9a06b9b73c8b0),[简书](http://www.jianshu.com/p/6ecaa414c702),[CSDN](http://blog.csdn.net/two_water/article/details/76408890),[个人博客](http://twowater.com.cn/2017/07/31/%E8%8D%89%E6%A0%B9%E5%AD%A6Python-%E4%B9%9D-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/)| \ No newline at end of file diff --git a/SUMMARY.md b/SUMMARY.md index 0748c59..1995653 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -42,4 +42,11 @@ - [模块的使用](/python8/2.md) - [主模块和非主模块](/python8/3.md) - [包](/python8/4.md) - - [作用域](/python8/5.md) \ No newline at end of file + - [作用域](/python8/5.md) +* [面向对象](/python9/Preface.md) + - [面向对象的概念](/python9/1.md) + - [类](/python9/2.md) + - [类的属性](/python9/3.md) + - [类的方法](/python9/4.md) + - [类的继承](/python9/5.md) + - [类的多态](/python9/6.md) \ No newline at end of file diff --git a/python9/1.md b/python9/1.md new file mode 100644 index 0000000..e40cb10 --- /dev/null +++ b/python9/1.md @@ -0,0 +1,32 @@ +# 一、面向对象的概念 # + +Python 是一门面向对象的语言, 面向对象是一种抽象,抽象是指用分类的眼光去看世界的一种方法。 用 JAVA 的编程思想来说就是:万事万物皆对象。也就是说在面向对象中,把构成问题事务分解成各个对象。 + +面向对象有三大特性,封装、继承和多态。 + +## 1、面向对象的两个基本概念 ## + +* **类** + +用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。 + +* **对象** + +通过类定义的数据结构实例 + + +## 2、面向对象的三大特性 ## + +* **继承** + +即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。 + +例如:一个 Dog 类型的对象派生自 Animal 类,这是模拟"是一个(is-a)"关系(例图,Dog 是一个 Animal )。 + +* **多态** + +它是指对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为。 + +* **封装性** + +“封装”就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体(即类);封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。 diff --git a/python9/2.md b/python9/2.md new file mode 100644 index 0000000..1b97070 --- /dev/null +++ b/python9/2.md @@ -0,0 +1,118 @@ +# 二、类 # + +## 1、定义类 ## + +类定义语法格式如下: + +```python +class ClassName: + + . + . + . + +``` + +一个类也是由属性和方法组成的,有些时候我们定义类的时候需要设置类的属性,因此这就需要构造函 + +类的构造函数如下: + +```python +def __init__(self,[...): +``` + +类定义了 __init__() 方法的话,类的实例化操作会自动调用 __init__() 方法。 + +那么如构造函数相对应的是析构函数,理所当然,一个类创建的时候我们可以用过构造函数设置属性,那么当一个类销毁的时候,就会调用析构函数。 + +析构函数语法如下: + +```python +def __del__(self,[...): +``` + +仔细观察的童鞋都会发现,类的方法与普通的函数有一个特别的区别,它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。 + +那么这个 self 代表什么呢? + +我们可以看下实例,通过实例来找出答案: + +```python +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +class Test: + def prt(self): + print(self) + print(self.__class__) + +t = Test() +t.prt() +``` + +观察输出的结果: + +![Python self](https://user-gold-cdn.xitu.io/2017/7/30/933b74a7ae0e312c40806ea8dad092d4) + +从执行结果可以很明显的看出,self 代表的是类的实例,输出的是当前对象的地址,而 `self.__class__` 则指向类。 + +当然 self 不是 python 关键字,也就是说我们把他换成其他的字符也是可以正常执行的。只不过我们习惯使用 self + +## 2、Python 定义类的历史遗留问题 ## + +Python 在版本的迭代中,有一个关于类的历史遗留问题,就是新式类和旧式类的问题,具体先看以下的代码: + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# 旧式类 +class OldClass: + pass + +# 新式类 +class NewClass(object): + pass + +``` + +可以看到,这里使用了两者中不同的方式定义类,可以看到最大的不同就是,新式类继承了`object` 类,在 Python2 中,我们定义类的时候最好定义新式类,当然在 Python3 中不存在这个问题了,因为 Python3 中所有类都是新式类。 + +那么新式类和旧式类有什么区别呢? + +运行下下面的那段代码: + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# 旧式类 +class OldClass: + def __init__(self, account, name): + self.account = account; + self.name = name; + + +# 新式类 +class NewClass(object): + def __init__(self, account, name): + self.account = account; + self.name = name; + + +if __name__ == '__main__': + old_class = OldClass(111111, 'OldClass') + print(old_class) + print(type(old_class)) + print(dir(old_class)) + print('\n') + new_class=NewClass(222222,'NewClass') + print(new_class) + print(type(new_class)) + print(dir(new_class)) + +``` + + +仔细观察输出的结果,对比一下,就能观察出来,注意喔,Pyhton3 中输出的结果是一模一样的,因为Python3 中没有新式类旧式类的问题。 + diff --git a/python9/3.md b/python9/3.md new file mode 100644 index 0000000..8d13385 --- /dev/null +++ b/python9/3.md @@ -0,0 +1,64 @@ +# 三、类的属性 # + +## 1、直接在类中定义属性 ## + +定义类的属性,当然最简单最直接的就是在类中定义,例如: + +```python +class UserInfo(object): + name='两点水' +``` + +## 2、在构造函数中定义属性 ## + +故名思议,就是在构造对象的时候,对属性进行定义。 + +```python +class UserInfo(object): + def __init__(self,name): + self.name=name +``` + +## 3、属性的访问控制 ## + +在 Java 中,有 public (公共)属性 和 private (私有)属性,这可以对属性进行访问控制。那么在 Python 中有没有属性的访问控制呢? + +一般情况下,我们会使用 `__private_attrs` 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 `self.__private_attrs`。 + +为什么只能说一般情况下呢?因为实际上, Python 中是没有提供私有属性等功能的。但是 Python 对属性的访问控制是靠程序员自觉的。为什么这么说呢?看看下面的示例: + +![Python 属性访问控制](https://user-gold-cdn.xitu.io/2017/7/28/cf3ef904a9c84bd15245cd1f0e1f3e88) + +仔细看图片,为什么说双下划线不是真正的私有属性呢?我们看下下面的例子,用下面的例子来验证: + +```python + +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +class UserInfo(object): + def __init__(self, name, age, account): + self.name = name + self._age = age + self.__account = account + + def get_account(self): + return self.__account + + +if __name__ == '__main__': + userInfo = UserInfo('两点水', 23, 347073565); + # 打印所有属性 + print(dir(userInfo)) + # 打印构造函数中的属性 + print(userInfo.__dict__) + print(userInfo.get_account()) + # 用于验证双下划线是否是真正的私有属性 + print(userInfo._UserInfo__account) + + +``` + +输出的结果如下图: + +![Python 属性访问控制](https://user-gold-cdn.xitu.io/2017/7/28/b147b0390a9b4cbcd5765658b54c12e9) \ No newline at end of file diff --git a/python9/4.md b/python9/4.md new file mode 100644 index 0000000..45bc176 --- /dev/null +++ b/python9/4.md @@ -0,0 +1,106 @@ +# 四、类的方法 # + +## 1、类专有的方法 ## + +一个类创建的时候,就会包含一些方法,主要有以下方法: + +类的专有方法: + +| 方法 | 说明 | +| ------| ------ | +|`__init__` |构造函数,在生成对象时调用| +|`__del__ `| 析构函数,释放对象时使用| +|`__repr__ `| 打印,转换| +|`__setitem__ `| 按照索引赋值| +|`__getitem__`| 按照索引获取值| +|`__len__`| 获得长度| +|`__cmp__`| 比较运算| +|`__call__`| 函数调用| +|`__add__`| 加运算| +|`__sub__`| 减运算| +|`__mul__`|乘运算| +|`__div__`| 除运算| +|`__mod__`| 求余运算| +|`__pow__`|乘方| + +当然有些时候我们需要获取类的相关信息,我们可以使用如下的方法: + +* `type(obj)`:来获取对象的相应类型; +* `isinstance(obj, type)`:判断对象是否为指定的 type 类型的实例; +* `hasattr(obj, attr)`:判断对象是否具有指定属性/方法; +* `getattr(obj, attr[, default])` 获取属性/方法的值, 要是没有对应的属性则返回 default 值(前提是设置了 default),否则会抛出 AttributeError 异常; +* `setattr(obj, attr, value)`:设定该属性/方法的值,类似于 obj.attr=value; +* `dir(obj)`:可以获取相应对象的所有属性和方法名的列表: + +## 2、方法的访问控制 ## + +其实我们也可以把方法看成是类的属性的,那么方法的访问控制也是跟属性是一样的,也是没有实质上的私有方法。一切都是靠程序员自觉遵守 Python 的编程规范。 + +示例如下,具体规则也是跟属性一样的, + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +class User(object): + def upgrade(self): + pass + + def _buy_equipment(self): + pass + + def __pk(self): + pass + +``` + +## 3、方法的装饰器 ## + + +* **@classmethod** +调用的时候直接使用类名类调用,而不是某个对象 + +* **@property** +可以像访问属性一样调用方法 + +具体的使用看下实例: + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +class UserInfo(object): + lv = 5 + + def __init__(self, name, age, account): + self.name = name + self._age = age + self.__account = account + + def get_account(self): + return self.__account + + @classmethod + def get_name(cls): + return cls.lv + + @property + def get_age(self): + return self._age + + +if __name__ == '__main__': + userInfo = UserInfo('两点水', 23, 347073565); + # 打印所有属性 + print(dir(userInfo)) + # 打印构造函数中的属性 + print(userInfo.__dict__) + # 直接使用类名类调用,而不是某个对象 + print(UserInfo.lv) + # 像访问属性一样调用方法(注意看get_age是没有括号的) + print(userInfo.get_age) +``` + +运行的结果: + +![Python 方法的装饰器](https://user-gold-cdn.xitu.io/2017/7/29/94ae6aec01a94136951cbb8314008781) diff --git a/python9/5.md b/python9/5.md new file mode 100644 index 0000000..1e34afa --- /dev/null +++ b/python9/5.md @@ -0,0 +1,170 @@ +# 五、类的继承 # + +## 1、定义类的继承 ## + +首先我们来看下类的继承的基本语法: + +```python +class ClassName(BaseClassName): + + . + . + . + +``` + +在定义类的时候,可以在括号里写继承的类,一开始也提到过,如果不用继承类的时候,也要写继承 object 类,因为在 Python 中 object 类是一切类的父类。 + +当然上面的是单继承,Python 也是支持多继承的,具体的语法如下: + +```python +class ClassName(Base1,Base2,Base3): + + . + . + . + +``` + +多继承有一点需要注意的:若是父类中有相同的方法名,而在子类使用时未指定,python 在圆括号中父类的顺序,从左至右搜索 , 即方法在子类中未找到时,从左到右查找父类中是否包含方法。 + +那么继承的子类可以干什么呢? + +继承的子类的好处: +* 会继承父类的属性和方法 +* 可以自己定义,覆盖父类的属性和方法 + +## 2、调用父类的方法 ## + +一个类继承了父类后,可以直接调用父类的方法的,比如下面的例子,`UserInfo2` 继承自父类 `UserInfo` ,可以直接调用父类的 `get_account` 方法。 + +```python +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +class UserInfo(object): + lv = 5 + + def __init__(self, name, age, account): + self.name = name + self._age = age + self.__account = account + + def get_account(self): + return self.__account + + +class UserInfo2(UserInfo): + pass + + +if __name__ == '__main__': + userInfo2 = UserInfo2('两点水', 23, 347073565); + print(userInfo2.get_account()) + +``` + +## 3、父类方法的重写 ## + +当然,也可以重写父类的方法。 + +示例: + +```python +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +class UserInfo(object): + lv = 5 + + def __init__(self, name, age, account): + self.name = name + self._age = age + self.__account = account + + def get_account(self): + return self.__account + + @classmethod + def get_name(cls): + return cls.lv + + @property + def get_age(self): + return self._age + + +class UserInfo2(UserInfo): + def __init__(self, name, age, account, sex): + super(UserInfo2, self).__init__(name, age, account) + self.sex = sex; + + +if __name__ == '__main__': + userInfo2 = UserInfo2('两点水', 23, 347073565, '男'); + # 打印所有属性 + print(dir(userInfo2)) + # 打印构造函数中的属性 + print(userInfo2.__dict__) + print(UserInfo2.get_name()) + +``` + +最后打印的结果: + +![Python 类的继承](https://user-gold-cdn.xitu.io/2017/7/29/a953f75e593c5a0586b06a28abc323d9) + +这里就是重写了父类的构造函数。 + + +## 3、子类的类型判断 ## + +对于 class 的继承关系来说,有些时候我们需要判断 class 的类型,该怎么办呢? + +可以使用 `isinstance()` 函数, + +一个例子就能看懂 `isinstance()` 函数的用法了。 + +```python +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +class User1(object): + pass + + +class User2(User1): + pass + + +class User3(User2): + pass + + +if __name__ == '__main__': + user1 = User1() + user2 = User2() + user3 = User3() + # isinstance()就可以告诉我们,一个对象是否是某种类型 + print(isinstance(user3, User2)) + print(isinstance(user3, User1)) + print(isinstance(user3, User3)) + # 基本类型也可以用isinstance()判断 + print(isinstance('两点水', str)) + print(isinstance(347073565, int)) + print(isinstance(347073565, str)) + +``` + +输出的结果如下: + +```txt +True +True +True +True +True +False +``` + +可以看到 `isinstance()` 不仅可以告诉我们,一个对象是否是某种类型,也可以用于基本类型的判断。 \ No newline at end of file diff --git a/python9/6.md b/python9/6.md new file mode 100644 index 0000000..da1b03d --- /dev/null +++ b/python9/6.md @@ -0,0 +1,67 @@ +# 六、类的多态 # + +多态的概念其实不难理解,它是指对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为。 + +事实上,我们经常用到多态的性质,比如: + +``` +>>> 1 + 2 +3 +>>> 'a' + 'b' +'ab' +``` + +可以看到,我们对两个整数进行 + 操作,会返回它们的和,对两个字符进行相同的 + 操作,会返回拼接后的字符串。也就是说,不同类型的对象对同一消息会作出不同的响应。 + + +看下面的实例,来了解多态: + + +```python +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +class User(object): + def __init__(self, name): + self.name = name + + def printUser(self): + print('Hello !' + self.name) + + +class UserVip(User): + def printUser(self): + print('Hello ! 尊敬的Vip用户:' + self.name) + + +class UserGeneral(User): + def printUser(self): + print('Hello ! 尊敬的用户:' + self.name) + + +def printUserInfo(user): + user.printUser() + + +if __name__ == '__main__': + userVip = UserVip('两点水') + printUserInfo(userVip) + userGeneral = UserGeneral('水水水') + printUserInfo(userGeneral) + +``` + +输出的结果: + +```txt +Hello ! 尊敬的Vip用户:两点水 +Hello ! 尊敬的用户:水水水 +``` + +可以看到,userVip 和 userGeneral 是两个不同的对象,对它们调用 printUserInfo 方法,它们会自动调用实际类型的 printUser 方法,作出不同的响应。这就是多态的魅力。 + +要注意喔,有了继承,才有了多态,也会有不同类的对象对同一消息会作出不同的相应。 + + + +最后,本章的所有代码都可以在 [https://github.com/TwoWater/Python](https://github.com/TwoWater/Python) 上面找到,文章的内容和源文件都放在上面。同步更新到 Gitbooks。 \ No newline at end of file diff --git a/python9/Preface.md b/python9/Preface.md new file mode 100644 index 0000000..b21aa2e --- /dev/null +++ b/python9/Preface.md @@ -0,0 +1,10 @@ +# 前言 # + +这篇写的很纠结,不过还是写完了。弄了个很逊的公众号,如果对本文有兴趣,可以关注下公众号喔,会持续更新。 + + +![公众号](http://img.blog.csdn.net/20170730171715934?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVHdvX1dhdGVy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) + +# 目录 # + +![草根学Python(九)面向对象](https://user-gold-cdn.xitu.io/2017/7/30/4c851ddc1fd9de58d7d7f205b8010c6d) \ No newline at end of file