Python核心 - 面向对象编程
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。 OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。 为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息, 并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。 自定义的对象数据类型就是面向对象中的类(Class)的概念。
给对象发消息实际上就是调用对象对应的关联函数(或者叫绑定函数),我们称之为对象的方法(Method)。
面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。 Class是一种抽象概念,比如我们定义一个叫Person的Class指定人类这个概念, 而实例(Instance)则是一个个具体的Person,比如,张三和李四是两个具体的Person。
所以,面向对象的设计思想是抽象出Class,根据Class创建Instance。 之前面向过程或函数式编程时我们通常说程序设计等价于算法+数据结构。 算法和数据是分开的,而面向对象的抽象程度又比函数要高,因为一个Class既包含数据,又包含操作数据的方法。
类的定义
最基本的方式
| |
第一个__init__是实例初始化会调用的方法,第二个自定义方法。
所有方法第一个参数必须是self,调用方法时这个参数不需要传递。
和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量, 虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同。你在实例化后可以给他再增加属性。
单下划线_和双下划线__
PEP 8 原话:“Use one leading underscore only for non-public methods and instance variables.”
在模块中:
- 单下划线_表示这个属性和函数是私有的,不应该直接访问
- 双下划线没有什么意义
- 对于
from module import *这样的导入,不管单下划线还是双下划线都不会被导入 - 对于
import module这样的导入都可以使用,但不建议使用,PEP8会告警调用单下划线_
在类中:
- 单下划线
_表示方法是私有方法或属性,不建议直接访问,PEP8会告警 - 双下划线
__表示final方法或属性防止被子类覆盖,Python 会自动将__attr改写为_ClassName__attr,可用来定义私有属性和方法 - 前后双下划线比如
__init__是python内部特殊的名字,自己没事就别定义这样的东西了
不管是模块还是类,要实现私有方法或属性,除非你有明确理由需要防止子类覆盖,否则一律用单下划线。
何时可以考虑双下划线?
- 你正在编写一个会被大量第三方子类化的框架/库,且某些属性极易被意外重名(例如
__update这种通用名称)。 - 需要实现特殊方法不冲突(如
__eq__、__hash__,这些是双下划线开头结尾的协议方法,不是 private 用途)。
总的来说就是,Python 相信调用者会遵守约定,而非通过语法强制封闭。
继承和多态
基本用法
| |
获取对象的信息:
| |
pythony允许多继承,也就是我们通常所说的MixIn。MixIn的目的就是给一个类增加多个功能,在设计类的时候, 我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。
比如,编写一个多进程模式的TCP服务,定义如下:
| |
编写一个多线程模式的UDP服务,定义如下:
| |
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类
使用__slots__
给一个实例绑定一个新的方法:
| |
如果我们想要限制实例的属性怎么办? Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
| |
注:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
使用@property
python最佳编程实践推荐我们不要像java那样去调用getter和setter,而是使用装饰器@property
Python内置的@property装饰器就是负责把一个方法变成属性调用
把一个getter方法变成属性,只需要加上@property就可以了, 此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
| |
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性
枚举类
通常我们需要用到常量,并且是一些有意义的常量。我们可以通过枚举类Enum实现
| |
使用元类
这个已经在"python核心-元类"里面讲解很详细,这里省略…