本篇,我们说说 Python 中的面向对象高级编程的基本概念。
数据封装、继承和多态只是面向对象程序设计中最基础的 3 个概念。在 Python 中,面向对象还有很多高级特性,允许我们写出非常强大的功能。本篇,我们会说说多重继承、定制类等概念。
__slots__
正常情况下,当我们定义了一个 class,创建了一个 class 的实例后,我们可以给该实例绑定任何属性和方法:
|
但是,给一个实例绑定的方法,对另一个实例是不起作用的,为了给所有实例都绑定方法,可以给 class 绑定方法:
|
为了达到限制的目的,Python 允许在定义 class 的时候,定义一个特殊的 __slots__ 变量,来限制该 class 实例能添加的属性:
|
试图绑定 __slots__ 元组中不存在的字段名,将得到 AttributeError 的错误。
注意: __slots__ 定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
@property
Python 内置的 @property 装饰器就是负责把一个方法变成属性调用:
|
把一个 getter 方法变成属性,只需要加上 @property 就可以了,此时,@property 本身又创建了另一个装饰器 @score.setter,负责把一个 setter 方法变成属性赋值,还可以定义只读属性,只定义 getter 方法,不定义 setter 方法就是一个只读属性。
多重继承
通过多重继承,一个子类就可以同时获得多个父类的所有功能。
在设计类的继承关系时,通常,主线都是单一继承下来的,但是,如果需要”混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为 MixIn。
Python 自带的很多库也使用了 MixIn。举个例子,Python 自带了 TCPServer 和 UDPServer 这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由 ForkingMixIn 和 ThreadingMixIn 提供。通过组合,我们就可以创造出合适的服务来。
定制类
看到类似 __slots__ 这种形如 __xxx__ 的变量或者函数名就要注意,这些在 Python 中是有特殊用途的。
__slots__ 我们已经知道怎么用了,__len__() 方法我们也知道是为了能让 class 作用于 len() 函数。
除此之外,Python 的 class 中还有许多这样有特殊用途的函数,可以帮助我们定制类。
__str__
__str__ 就相当于 Objective-C 中的 Description 方法或 C# 中的 toString() 方法。
|
__iter__ 和 __next__
果一个类想被用于 for … in 循环,类似 list 或 tuple,就必须实现一个 __iter__() 方法,该方法返回一个迭代对象,然后,Python 的 for 循环就会不断调用该迭代对象的 __next__() 方法拿到循环的下一个值,直到遇到 StopIteration 错误时退出循环。
|
__getitem__
Fib 实例虽然能作用于 for 循环,看起来和 list 有点像,但是,把它当成 list 来使用还是不行,比如,取第 5 个元素:
|
要表现得像 list 那样按照下标取出元素,需要实现 __getitem__() 方法:
|
__getattr__
之前说过,当我们调用类的方法或属性时,如果不存在,就会报错。
Python 有一个机制,那就是写一个 __getattr__() 方法,动态返回一个属性:
|
当调用不存在的属性时,比如 score,Python 解释器会试图调用 __getattr__(self, ‘score’) 来尝试获得属性,这样,我们就有机会返回 score 的值。
注意,只有在没有找到属性的情况下,才调用 __getattr__,已有的属性,比如 name,不会在 __getattr__ 中查找。