簡體   English   中英

'super'對象在python3中沒有屬性'__getattr__'

[英]'super' object has no attribute '__getattr__' in python3

如何用python 3和繼承覆蓋__getattr__

當我使用以下內容時:

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

我收到這個錯誤。

>>> e  = Example()
>>> e.a
'MixinA'
>>> e.b
'MixinB'
>>> e.c
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
...
AttributeError: 'super' object has no attribute '__getattr__'  

難道我只能獲取引用原始類和屬性的屬性錯誤嗎? 也就是說:

AttributeError: 'Example' object has no attribute 'c'

PS:我發現這個帖子'超級'對象沒有調用__getattr__但是我不確定是否有解決方案。

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)

簡而言之,如果您認為應該實現__getattribute__而不是__getattr__那么您可能正在嘗試錯誤的方法,除非在非常具體的情況下。 你可能在這里不知道的是:如果所需名稱的普通屬性不存在,則不會調用__getattr__ ,因此不需要在超類中調用它(除非超類是大小寫的)不是對象,並具有已知的自定義)

編輯

或者,只需檢查下一個超類是否以最簡單的方式擁有__getattr__

...
if hasattr(super(), "__getattr__"):
    return super().__getattr__(attr)
raise AttributeError

如果你想用mixin風格的類做事,那么你需要創建一個始終引發AttributeError的base-attribute-getting-class。

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)

但是,屬性允許您以更簡單,更簡潔的方式執行此操作。

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM