Mic*_*ael 14 python python-3.x python-3.4
如何覆盖__getattr__python 3和继承?
当我使用以下内容时:
class MixinA:
def __getattr__(self, item):
# Process item and return value if known
if item == 'a':
return 'MixinA'
# If it is unknown, pass it along to give
# a chance to another class to handle it
return super().__getattr__(item)
class MixinB:
def __getattr__(self, item):
# Process item and return value if known
if item == 'b':
return 'MixinB'
# If it is unknown, pass it along to give
# a chance to another class to handle it
return super().__getattr__(item)
class Example(MixinA, MixinB):
# main class
pass
Run Code Online (Sandbox Code Playgroud)
我收到这个错误.
>>> e = Example()
>>> e.a
'MixinA'
>>> e.b
'MixinB'
>>> e.c
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
...
AttributeError: 'super' object has no attribute '__getattr__'
Run Code Online (Sandbox Code Playgroud)
难道我只能获取引用原始类和属性的属性错误吗?也就是说:
AttributeError: 'Example' object has no attribute 'c'
Run Code Online (Sandbox Code Playgroud)
PS:我发现这个帖子'超级'对象没有调用__getattr__但是我不确定是否有解决方案.
jsb*_*eno 12
Python属性检索机制的工作方式是将类__getattr__称为"最后一个资源",以尝试获取该类实例的属性.
你的代码是正确的 - 由于你的超级类"示例" - 在这种情况下是"对象" - 没有__getattr__属性,它失败了.如果您不是深层次的层次结构,并且想要为直接从对象继承的类执行自定义属性检索(在Py3中可以表示为根本没有任何基础,就像在代码中那样) - 只需引发"AttributeError"如果您的自定义查找失败.
相反,如果你打算让自定义搜索优先于Python的普通属性retreival机制(而不是被称为后备),你应该实现__getattribute__而不是__getattr__.
在这种情况下,基类 - 对象 - 确实有一个__getattribute__必须调用普通属性检索的方法 - 问题是您必须为所需的一切调用它- 包括方法名称和已设置的已知属性.即:某事:
class Example:
def __init__(self):
self.attrs_to_override = ["attr1", "foo", "bar"]
def docustomstuff(self, attr):
...
def __getattribute__(self, attr):
getter = super().__getattribute__
if attr in getter("attrs_to_override"):
getter("docustomstuff")(attr)
return getter(attr)
Run Code Online (Sandbox Code Playgroud)
简而言之,如果你认为你应该实施__getattribute__而不是__getattr__你可能正在尝试错误的方法,除非在非常具体的情况下.你可能在这里不知道的是:__getattr__如果所需名称的普通属性不存在,则不会被调用,因此不需要在超类中调用它(除非超类不是对象并具有已知的自定义功能)
编辑
或者,只需检查下一个超类是否确实__getattr__以最简单的方式:
...
if hasattr(super(), "__getattr__"):
return super().__getattr__(attr)
raise AttributeError
Run Code Online (Sandbox Code Playgroud)
如果你想用mixin风格的类做事,那么你需要创建一个总是引发一个的base-attribute-getting-class AttributeError.
class AttrGetter:
def __getattr__(self, item):
raise AttributeError(item)
class MixinA(AttrGetter):
def __getattr__(self, item):
if item == 'a':
return 'MixinA'
return super().__getattr__(item)
class MixinB(AttrGetter):
def __getattr__(self, item):
if item == 'b':
return 'MixinB'
return super().__getattr__(item)
class Example(MixinA, MixinB):
pass
# mro stands for method resolution order.
# It defines the order in which classes are searched for attributes.
# We're looking for __getattr__ in this circumstance.
print(Example.mro())
# [<class '__main__.Example'>, <class '__main__.MixinA'>, <class '__main__.MixinB'>,
# <class '__main__.AttrGetter'>, <class 'object'>]
# As you can see, searches for __getattr__ only check AttrGetter after having checked
# both mixins first.
e = Example()
print(e.a)
print(e.b)
print(e.c)
Run Code Online (Sandbox Code Playgroud)
但是,属性允许您以更简单,更简洁的方式执行此操作.
class MixinA:
@property
def a(self):
return "MixinA"
class MixinB:
@property
def b(self):
return "MixinB"
class Example(MixinA, MixinB):
pass
e = Example()
print(e.a)
print(e.b)
print(e.c)
Run Code Online (Sandbox Code Playgroud)