如何__getattribute__
使用该方法?
在普通的点分查找之前调用它。如果涨了AttributeError
,我们打电话__getattr__
。
这种方法很少使用。标准库中只有两个定义:
$ grep -Erl "def __getattribute__\(self" cpython/Lib | grep -v "/test/"
cpython/Lib/_threading_local.py
cpython/Lib/importlib/util.py
最佳实践
以编程方式控制对单个属性的访问的正确方法是使用property
。类的D
编写应如下所示(可以使用setter和Deleter来复制明显的预期行为):
class D(object):
def __init__(self):
self.test2=21
@property
def test(self):
return 0.
@test.setter
def test(self, value):
'''dummy function to avoid AttributeError on setting property'''
@test.deleter
def test(self):
'''dummy function to avoid AttributeError on deleting property'''
和用法:
>>> o = D()
>>> o.test
0.0
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
属性是数据描述符,因此它是常规点分查找算法中要查找的第一件事。
的选项 __getattribute__
如果您绝对需要通过来为每个属性实现查找,则有几种选择__getattribute__
。
- 提高
AttributeError
,导致__getattr__
被调用(如果已实现)
- 从中退还东西
- 通过
super
调用父类的(可能object
的)执行
- 呼唤
__getattr__
- 以某种方式实现您自己的虚线查找算法
例如:
class NoisyAttributes(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self, name):
print('getting: ' + name)
try:
return super(NoisyAttributes, self).__getattribute__(name)
except AttributeError:
print('oh no, AttributeError caught and reraising')
raise
def __getattr__(self, name):
"""Called if __getattribute__ raises AttributeError"""
return 'close but no ' + name
>>> n = NoisyAttributes()
>>> nfoo = n.foo
getting: foo
oh no, AttributeError caught and reraising
>>> nfoo
'close but no foo'
>>> n.test
getting: test
20
您最初想要的。
此示例说明了如何执行您最初想要的操作:
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else:
return super(D, self).__getattribute__(name)
并且会像这样:
>>> o = D()
>>> o.test = 'foo'
>>> o.test
0.0
>>> del o.test
>>> o.test
0.0
>>> del o.test
Traceback (most recent call last):
File "<pyshell#216>", line 1, in <module>
del o.test
AttributeError: test
代码审查
您的代码带注释。您在中对自己进行了点查询__getattribute__
。这就是为什么您会得到递归错误的原因。您可以检查名称是否可用,"__dict__"
并使用它super
来解决,但这并不覆盖__slots__
。我将其留给读者练习。
class D(object):
def __init__(self):
self.test=20
self.test2=21
def __getattribute__(self,name):
if name=='test':
return 0.
else: # v--- Dotted lookup on self in __getattribute__
return self.__dict__[name]
>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp