Python学习笔记18:类II
在Python学习笔记9:类中我们介绍了一些基础的类定义和使用方式,我们这里用OOP的原则对其进行重新审视,并且补充没有说到的部分。
封装
关于封装,在前文中我们介绍了简单的封装方式,即如何用前缀_
或__
来实现类似的访问修饰符的作用。
但有一点我们没有说明,即如何实现类方法。
我们知道,类方法和对象方法最大的不同是不依赖于对象的属性,当然也不存在对象指针或引用。
class sampleCls:
@classmethod
def classMethod(cls):
print(cls)
print("this is a class method")
def objMethod(self):
print(self)
print("this is a object method")
a = sampleCls()
a.objMethod()
sampleCls.classMethod()
输出
<main.sampleCls object at 0x000001B09038B760>
this is a object method
<class ‘main.sampleCls’>
this is a class method
从上边我们可以看到,通过使用函数修饰符classmethod
,我们定义了一个类方法classMethod
。
而最终的打印结果也表明了这两个方法持有的引用分别是对象和类。
继承
在继承上,Python与传统编程语言有很大不同,它支持多继承。
我们来看一个稍显复杂的例子:
class A:
def __init__(self):
print("A.__init__()")
class B(A):
def __init__(self):
super().__init__()
print("B.__init__()")
class C(A):
def __init__(self):
super().__init__()
print("C.__init__()")
class D(B,C):
def __init__(self):
super().__init__()
print("D.__init__()")
d = D()
print(D.__mro__)
输出:
A.init()
C.init()
B.init()
D.init()
(<class ‘main.D’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.A’>, <class ‘object’>)
从输出我们可以观察到,这个继承关系创建过程是A>C>B>D,而且这其中虽然C和B都继承了A,但解释器很聪明,只创建了一次A。
我们这里除了在构造函数中输出以观察构建过程,还通过D.__mro__
输出了一个继承关系链。
关于MRO,《Python Cookbook》一书是这么解释的:
对于你定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。
我画了一个简单的类图来说明上边的继承关系和MRO检索顺序:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tj6DwTit-1616934528932)(https://i.loli.net/2021/03/28/Ek6YPH23X5m7GWO.png)]
关于MRO检索顺序,《Python Cookbook》是这么说的:
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
我们这个例子已经显得很混乱了,如果遇到继承层级更复杂的局面,要理清继承链的难度可想而知。我的建议是使用clsName.__mro__
查看解释器实际的继承链,再结合UML图理清继承关系。
至于这么做的必要性,如果你的继承链上有同名函数互相覆盖,那理清继承链才能确切知道哪个会覆盖哪个。
多态
说到多态,其核心内容肯定是抽象类和接口,而在Python中这是一回事。
from abc import ABCMeta, abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def fly(self):
'''这是一个抽象方法'''
pass
class SubBase(Base):
def fly(self):
print("I can fly")
# base = Base() 会报错,因为抽象类不能实例化
base = SubBase()
base.fly()
借助abc
模块,我们可以实现一个抽象基类,接口与之类似,因为Python是支持多继承的。
这里
metaclass=ABCMeta
属于元编程的范围,我们不多做讨论。
关于Python中类的更多内容,可以阅读《Python Cookbook》的相关章节。