证明验证了
self.__dict__
可以触发描述符中的__getattribute__
。
class Room:
def __init__(self,name):
self.name = name
def __getattribute__(self,key):
print('in __getattribute__',key)
return object.__getattribute__(self,key)
def __setattr__(self,attr,value):
print('in __setattr__',attr)
self.__dict__[attr] = value
print('over')
创建一个实例,我在输出信息中添加一些以
#
开头的注释:
x = Room('r1')
# self.name = name in __init__ trigger __setattr__
in __setattr__ name
# python interpreter read part of self.__dict__[attr] = value,extract self.__dict__ to trigger __getattribute__.
in __getattribute__ __dict__
over
我们看到Python解释器可以提取整行字符串的一部分来触发
__getattribute__
方法。
class Sample:
def __init__(self, name):
self.name = name
def __get__(self,instance,owner):
print('get called')
def __set__(self, instance, value):
print('set called')
class Person:
name = Sample('name')
举个例子:
p = Person()
p.name
get called
p.name
可以触发__get__
p.name = 'tom'
set called
对于命令
p.name = 'tom'
,为什么Python解释器不提取p.name
调用__get__
然后让p.name = 'tom'
调用__set__
?为什么输出不是如下所示?
p.name = 'tom'
get called # p.name trigger
set called # p.name = 'tom' trigger
Assignemts 将为普通对象触发
__setattr__
,并调用描述符中的 __set__
方法,如您所验证。
您的第一个示例运行
__getattribute__
来检索实例 __dict__
的唯一原因是因为 您的 __setattr__
的自定义实现会这样做。
默认的
__setattr__
通常会在实例 __dict__
中创建一个条目,但该条目将使用内部槽在本机代码中引用,并且不会通过 __gettattribute__
重定向。
您可以通过 callign
__setattr__
使用默认的 super()
实现来轻松验证这一点,而不是自己创建字典条目:
class Room:
def __init__(self,name):
self.name = name
def __getattribute__(self,key):
print('in __getattribute__',key)
return object.__getattribute__(self,key)
def __setattr__(self,attr,value):
print('in __setattr__',attr)
super().__setattr__(attr, value)
print('over')
在交互式翻译器中:
In [35]: r = Room("blah")
in __setattr__ name
over
In [36]: r.name
in __getattribute__ name
Out[36]: 'blah'
In [37]: r.__dict__
in __getattribute__ __dict__
Out[37]: {'name': 'blah'}
因此,您在描述符中的
__set__
中观察到的行为是普通行为。