繁体   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