【发布时间】:2010-03-08 23:29:32
【问题描述】:
我想重写一个类上的__getattr__ 方法来做一些花哨的事情,但我不想破坏默认行为。
这样做的正确方法是什么?
【问题讨论】:
-
“中断”,而不是“改变”。这很清楚:“花式”属性不应该干扰内置属性,并且应该尽可能地像它们一样表现。迈克尔的回答既正确又有帮助。
标签: python getattr getproperty
我想重写一个类上的__getattr__ 方法来做一些花哨的事情,但我不想破坏默认行为。
这样做的正确方法是什么?
【问题讨论】:
标签: python getattr getproperty
覆盖__getattr__ 应该没问题——__getattr__ 仅作为最后的手段调用,即如果实例中没有与名称匹配的属性。例如,如果您访问foo.bar,那么只有在foo 没有名为bar 的属性时才会调用__getattr__。如果该属性是您不想处理的属性,请提出AttributeError:
class Foo(object):
def __getattr__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
raise AttributeError
但是,与__getattr__ 不同,__getattribute__ 将首先被调用(仅适用于新样式类,即那些从对象继承的类)。在这种情况下,您可以像这样保留默认行为:
class Foo(object):
def __getattribute__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
return object.__getattribute__(self, name)
【讨论】:
__getattr__ 中调用 super —— 知道该怎么做吗? (AttributeError: 'super' object has no attribute '__getattr__')
AttributeError 没有异常 args 中属性的上下文。
class A(object):
def __init__(self):
self.a = 42
def __getattr__(self, attr):
if attr in ["b", "c"]:
return 42
raise AttributeError("%r object has no attribute %r" %
(self.__class__.__name__, attr))
>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False
【讨论】:
self.__class__.__name__ 而不是self.__class__,以防类覆盖__repr__
为了扩展迈克尔的回答,如果你想使用__getattr__ 保持默认行为,你可以这样做:
class Foo(object):
def __getattr__(self, name):
if name == 'something':
return 42
# Default behaviour
return self.__getattribute__(name)
现在异常消息更具描述性:
>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'
【讨论】:
__getattr__ 和__getattribute__?
return super().__getattribute__(name) ,以防万一你在这个类中也有__getattribute__方法。