我在实现属性__getattr__时遇到了困难,因此当发生错误时,会正确报告.这是我的MWE(python 3.6):
class A:
@property
def F(self):
return self.moo # here should be an error
@property
def G(self):
return self.F
def __getattr__(self, name):
print('call of __getattr__ with name =', name)
if name == 'foo':
return 0
raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, name))
a = A()
print(a.G)
Run Code Online (Sandbox Code Playgroud)
输出如下:
call of __getattr__ with name = moo
call of __getattr__ with name = F
call of __getattr__ with name = G
Traceback (most recent call last):
line 18 in <module>
print(a.G)
line 15, in __getattr__
raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, name))
AttributeError: 'A' object has no attribute 'G'
Run Code Online (Sandbox Code Playgroud)
但应该提出的错误是:
AttributeError: 'A' object has no attribute 'moo'
Run Code Online (Sandbox Code Playgroud)
我知道在无错误的场景中调用__dict__之前尝试过的属性和属性__getattr__.
我觉得当一个属性存在但失败时,__getattr__仍然会尝试而不是让属性中的错误通过.如何避免这种情况?
生成的有关未能获取属性的初始错误消息'foo'已丢失.最后的错误消息'A' object has no attribute 'G'特别容易引起误解和烦扰.如何实现__getattr__才能看到初始错误?
(编辑)一个相关的问题是同时实现
hasattr(a, 'moo')返回,False同时hasattr(a, 'G')返回True或引发缺失'moo'属性的异常.那有意义吗?
首先,有点了解为什么会发生这种情况.来自以下文件__getattr__:
当默认属性访问因AttributeError [...]或
__get__()name属性失败时调用,引发AttributeError.
在这种情况下,由于您正在使用@property,我们正在尝试恢复时AttributeError从__get__属性方法中提取.这就是你的调用栈在那一刻的样子.Fself.moo
__main__
a.G.__get__
a.F.__get__
a.__getattr__ # called with 'moo' <-- this is where the error is raised
Run Code Online (Sandbox Code Playgroud)
属性getter协议看到从内部引发的错误a.F.__get__,因此它在调用时回退a.__getattr__('F'),尽管由于错误而引发了错误'moo'.然后发生同样的事情a.G.__get__
这种行为在Python中被认为是正常的,因为无法返回值的最顶层属性确实存在a.G.
现在你想要的是AttributeError通过一种__get__方法来提升而不是被抓住.要做到这一点,你需要不要有一个__getattr__方法.
因此,在这种特殊情况下,您想要使用的是__getattribute__.
当然,使用此解决方案,您必须确保自己不要覆盖现有属性.
class A:
@property
def F(self):
return self.moo # here should be an error
@property
def G(self):
return self.F
def __getattribute__(self, name):
print('call of __getattribute__ with name =', name)
if name == 'foo':
return 0
else:
return super().__getattribute__(name)
Run Code Online (Sandbox Code Playgroud)
A().G
Run Code Online (Sandbox Code Playgroud)
call of __getattribute__ with name = G
call of __getattribute__ with name = F
call of __getattribute__ with name = moo
Traceback (most recent call last):
...
AttributeError: 'A' object has no attribute 'moo'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1379 次 |
| 最近记录: |