第一个演示:
class B:
def __init__(self):
self.name = '234'
# def __getattribute__(self, name):
# print('getattr')
def __getattr__(self, name):
print('get')
def __setattr__(self, name, value):
print('set')
def __delattr__(self, name):
print('del')
b = B()
print(b.__dict__)
b.name
b.__dict__
是{}
,但是第二个演示:
class B:
def __init__(self):
self.name = '234'
def __getattribute__(self, name):
print('getattr')
def __getattr__(self, name):
print('get')
def __setattr__(self, name, value):
print('set')
def __delattr__(self, name):
print('del')
b = B()
print(b.__dict__)
b.name
b.__dict__
是None
,为什么?并且b.__dict__
会调用__getattribute__
,但不会调用__getattr__
,这是否意味着__getattribute__
会阻止调用__getattr__
?
答案 0 :(得分:5)
为所有属性访问(获取,设置和删除)调用__getattribute__
,__setattr__
和__delattr__
方法。另一方面,__getattr__
仅调用缺少的属性;它通常不会已实现,但如果是,则__getattribute__
会调用它,否则无法找到该属性,或AttributeError
引发了__getattribute__
。
您使用除了打印并返回None
之外什么都不做的方法替换了3个主要方法的标准实现(默认情况下没有明确的return
语句)。 __dict__
只是另一种属性访问权限,您的__getattribute__
方法会返回None
,并且永远不会调用__getattr__
或提升AttributeError
。
来自Customizing attribute access documentation:
object.__getattr__(self, name)
当属性查找未在通常位置找到属性时调用(即,它不是实例属性,也不在self
的类树中找到。)
和
object.__getattribute__(self, name)
无条件调用以实现类的实例的属性访问。 如果该类还定义了__getattr__()
,则除非__getattribute__()
明确调用它或引发AttributeError
,否则不会调用后者。
(大胆强调我的)。
调用基本实现(通过super().__getattribute__
)或引发AttributeError
:
>>> class B:
... def __init__(self):
... self.name = '234'
... def __getattribute__(self, name):
... print('getattr')
... return super().__getattribute__(name)
... def __getattr__(self, name):
... print('get')
... def __setattr__(self, name, value):
... print('set')
... def __delattr__(self, name):
... print('del')
...
>>> b = B()
set
>>> b.__dict__
getattr
{}
>>> b.name
getattr
get
>>> class B:
... def __init__(self):
... self.name = '234'
... def __getattribute__(self, name):
... print('getattr')
... raise AttributeError(name)
... def __getattr__(self, name):
... print('get')
... def __setattr__(self, name, value):
... print('set')
... def __delattr__(self, name):
... print('del')
...
>>> b = B()
set
>>> b.__dict__
getattr
get
>>> b.name
getattr
get
请注意,通过调用super().__getattribute__
,可以找到实际的__dict__
属性。通过引发AttributeError
,__getattr__
被调用,也返回None
。