Python学习笔记18:类II

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
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()
(main.D’>, main.B’>, main.C’>, main.A’>, )

从输出我们可以观察到,这个继承关系创建过程是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》的相关章节

你可能感兴趣的:(Python,python,oop,类)