属性:这里表示类(或类的实例)中的变量与方法的统称。
所以搜索顺序包括:类的属性搜索顺序、类的实例的属性搜索顺序。
下面是所有魔术方法同时出现的情况下,类或实例的属性搜索顺序。
默认搜索顺序
对于类,比如查找A.x。A是类,x是类的属性。
类属性的默认搜索顺序:A自己的x(即A的属性字典__dict__) ⟶ A的父类的x [1] ⟶ 父类的父类的x… ⟶ object的x
对于类的实例,比如查找a.x。a是A的实例,x是实例的属性。
实例的默认搜索顺序:a自己的x(即a的属性字典__dict__)⟶ a从父类的构造方法(__new__, __init__
)继承来的属性 ⟶ A自己的x ⟶ A的父类的x [1] ⟶ 父类的父类的x… ⟶ object的x
[1]:
如果A是单继承,直接不断向上找父类。如果A是多继承,由Python3的mro生成一个有序的继承列表,依次找父类。
相关的魔术方法
与搜索顺序相关的魔术方法有:
1、反射相关的:__getattr__, __setattr__, __delattr__, __getattribute__
2、描述器相关的:__get__,__set__,__delete__
下面是所有魔术方法同时出现的情况下,类或实例的属性搜索顺序:
实例属性搜索顺序
还是以 a.x 为例。
修改/删除 a.x 时
不管 x 这个属性是不是描述器,描述器不起作用:
修改a.x时,直接调 __setattr__
删除a.x时,直接调 __delattr__
因为修改/删除肯定是操作a自己的x,不会去操作继承位置的x,显然是直接调用类A的 __setattr__ 或 __delattr__。
读取 a.x 时
如果 x 是描述器:
1、非数据描述器时,描述器不起作用:
__getattribute__ ⟶ 实例默认搜索顺序 ⟶ __getattr__
2、数据描述器时:
__getattribute__ ⟶ 描述器的__get__
如果 x 不是描述器:
__getattribute__ ⟶ 实例默认搜索顺序 ⟶ __getattr__
类属性搜索顺序
修改/删除 A.x
与实例一样,是操作A自己的x,不存在搜索顺序。
修改时,比如A.x=100,赋值即重新定义。
读取 A.x
如果 x 是描述器:调描述器的 __get__
如果不是描述器:符合上文的 类属性的默认搜索顺序