簡體   English   中英

為什么在這種情況下對 super() 的調用不使用 __getattr__ ?

[英]Why is the call to super() not using __getattr__ in this case?

所以我有一個組合,為什么我的包裝器 class 包含 Pandas DataFrame。 因為我想向它添加一些行為,所以我設置了以下內容:

class DataFrameWrapper(dict):
    def __init__(self, dataframe, *args, **kwargs):
        self.df = dataframe
        self.pandas_callables = [method_name for method_name in dir(self.df)
                                    if callable(getattr(self.df, method_name))]
        super(DataFrameWrapper, self).__init__()

    def __getitem__(self, item):
        return self.df[item]

    def __getattr__(self, item):
        if item in self.pandas_callables:
            # this is a dataframe method call - forward to the dataframe & return that
            return object.__getattribute__(self.df, item)
        else:
            try:  # try to return our own attribute, if any
                return object.__getattribute__(self, item)
            except AttributeError as ex:
                # likely a panda attribute. IF not, then it's a genuine attribute
                # error, so we don't catch it and let it raise another exception
                return object.__getattribute__(self.df, item)

然后我說

class Foo(DataFrameWrapper):
    def __init__(self, dataframe,  *args, **kwargs):
        super().__init__(dataframe,  *args, **kwargs)

class Bar(Foo)
    """ concrete implementation class """

class Baz(Foo)
    """ concrete implementation class """

這樣我們就可以做到:

bar = Bar(df)
bar.to_json()
bar.some_custom_method()
col = bar["column_name"]

現在,如果我說:

json = bar.to_json()

這工作正常。 但是,我想在 Foo 中添加額外的處理,所以我想做:

class Foo(DataFrameWrapper):
   def to_json(*args, **kwrags)
      # do additional stuff
      super().to_json(*args, **kwrags)

但是在這種情況下, __getattr__()永遠不會在包裝器中調用,我只是得到

AttributeError: 'super' object has no attribute 'to_json'

為什么?

編輯:

如果我做一些愚蠢的事情,像這樣:

class DataFrameWrapper(dict):

    ### previous code unchanged ###

    def __getattribute__(self, item):
        if item == "to_json":
            return object.__getattr__(self, item)
        return object.__getattribute__(self, item)

然后調用 to_json() 就可以了。 根據文檔,我希望我剛剛所做的黑客行為無論如何都會發生。

好的,根據上面的@martineau 評論嘗試回答。

所以是的, super()實際上不僅僅是直接調用父級的方法。 因為 Python 支持多個 inheritance,所以對super().foo()的調用必須做的不僅僅是調用(第一個)父類' __getattribute__ 它必須建立一些機制來確保python對多個inheritance的實現是連貫的。

也就是說,如果我直接調用父母的方法(根據Python super()'s guide 的老派),那么它會按我最初的預期工作:

class Foo(DataFrameWrapper):
    def to_json(self, *args, **kwargs):
        # do stuff
        return DataFrameWrapper.__getattr__(self, "to_json")(*args, **kwargs)

從我獲得預期功能的意義上說,這“解決了”問題。

現在要了解為什么 super() 不起作用:

super有一個__getattribute__方法,但沒有一個__getattr__方法。 因此,我猜測發生的事情可能是這樣的:

  1. super().__getattribute__("to_json")被調用
  2. super通過MRO嘗試查找屬性
  3. 根據下面的評論,它會在每個類的字典中查找它正在尋找的屬性。 出於效率原因,猜測它實際上並沒有調用每個類的getattribute方法。
  4. 有關示例詳細信息,請參閱下面的評論。 也許最終我會將其構建為答案。

暫無
暫無

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

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