0%

Python中的属性搜索顺序

属性:这里表示类(或类的实例)中的变量与方法的统称。

所以搜索顺序包括:类的属性搜索顺序、类的实例的属性搜索顺序。

下面是所有魔术方法同时出现的情况下,类或实例的属性搜索顺序。

默认搜索顺序

对于类,比如查找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__

如果不是描述器:符合上文的 类属性的默认搜索顺序