从类或实例设置属性时的查找过程是什么?
问题内容:
Nutshell中的Python描述
了从类cls.name
获取属性时的查找过程,例如,以及从实例获取属性时的查找过程。obj.name
但是我不确定何时设置属性:
设置属性
请注意,仅当您引用属性而不绑定属性时,属性查找步骤才按照上述步骤进行。当您绑定(无论是类或实例)的属性,它的名字是不是特别的(除非
一个__setattr__
方法,或 将__set__
压倒一切的描述符的方法,截取一个实例属性的绑定),你只影响
了__dict__
该属性条目(分别在类或实例中)。换句话说,对于属性绑定,除了检查 覆盖描述符 之外,不涉及查找过程。
我的问题是:
-
设置类的属性时,例如“查找”过程是什么
cls.name=value
? -
设置对象的属性时,例如“查找”过程是什么
obj.name=value
?
该程序似乎涉及
- 该
__setattr__
方法
setattr (自身,名称,值)
在每个绑定属性的请求
x.y
(通常是赋值语句x.y=value
,但也有,例如setattr(x, 'y', value)
)上,Python都会调用x.__setattr__('y', value)
。Python始终要求__setattr__
在x上绑定任何属性-与__getattr__
(在这种意义上__setattr__
更接近__getattribute__
)有很大的不同。为了避免递归,当
x.__setattr__
bindsx
的属性时,它必须x.__dict__
直接修改(例如,通过x.__dict__[name]=value
);甚至更好的是,__setattr__
可以将设置委派给超类(通过super(C, x).__setattr__('y', value)
在v3中调用或justsuper().__setattr__('y', value)
)。Python会忽略的返回值__setattr__
。如果__setattr__
不存在(即从继承
object
),并且C.y
不是重写描述符,则Python通常会转换x.y=z
为x.__dict__['y']=z
。
-
__set__
重写描述符的 方法(所以我问 为什么object .__ get__
的所有者类有一个参数owner
,而object .__ set__
却没有?) -
__dict__
属性的 条目(分别在类或实例中)
鉴于本书区分了从类和实例中获取属性的查找过程,因此自然地认为从类中设置属性和从实例中设置属性时,“查找”过程是不同的。
但是由于在Python3中,每个类对象实际上都是其元类(例如,type
类)的实例,用于从类中设置属性的“查找”过程和用于从实例中设置属性的“查找”过程真的不同吗?
谢谢。
问题答案:
对于x.y = z
,Python的查找x.__setattr__
的方式绕过__getattribute__
,__getattr__
和x
自己的__dict__
,然后调用x.__setattr__('y', z)
。
自定义__setattr__
可以执行任何所需的操作,但这是默认设置:
- 搜索
type(x).__mro__
一个__dict__
匹配的属性名称条目。 - 如果此搜索找到
descr
具有__set__
方法的描述符(以与查找__set__
方式相同的方式查找__setattr__
),请调用descr.__set__(x, z)
。
2a。在非常不寻常的情况下,搜索会找到一个带__delete__
但不带的描述符__set__
,并引发AttributeError。
- 否则,设置
x.__dict__['y'] = z
或引发AttributeError
if ifx
no__dict__
。(这使用“ real”__dict__
,绕过了诸如此类mappingproxy
。)
这适用于类型和其他对象,但要注意的是它们type.__setattr__
将拒绝设置用C编写的类的属性,并且type.__setattr__
会进行一些额外的内部维护,除非您疯狂地做一些不被支持的事情以绕过它,否则您将不必担心。