【问题标题】:Python: RecursionError with Class InheritancePython:具有类继承的 RecursionError
【发布时间】:2020-05-16 15:36:08
【问题描述】:

我已经给了一个类A,方法是fg。在A.f的实现中,调用了self.g方法,即使用了A.g。 (我无法/愿意更改此类 A,因为它来自 python 包。)

现在我想建立一个A 的子类B 并想覆盖fg 方法。在B.f的实现中,我调用super().f,即使用A.f。在B.g.的实现中,我调用self.f,即使用B.f

我希望一切都定义明确: B.g 致电B.f 致电A.f 致电A.g

事实上,当我遇到无数次递归时,我得到了一个RecursionErrorB.g 致电B.f 致电A.f 致电B.g

我没有正确理解什么?

这是一个实现:

class A:
    def f(self):
        print('Method A.f was called.')
        self.g()

    def g(self):
        print('Method A.g was called.')

class B(A):
    def f(self):
        print('Method B.f was called.')
        super().f()

    def g(self):
        print('Method B.g was called.')
        self.f()

b = B()
b.g()

澄清一下:在我的应用程序中,A 是一个 scikit-learn 类,ffitgfit_transform。在这个 scikit-learn 类中,fit_transform 被显式覆盖,而fit 不幸地使用了fit_transform。为了确保我的子类B 不会从A 继承fit_transform,我必须以通常的方式重新定义它,这会导致如解释的那样无限递归。

【问题讨论】:

  • self.g() 实际上是 b.g(),就像您最初的通话一样。

标签: python class recursion infinite-recursion


【解决方案1】:

如你所说,B 的 g 方法会覆盖 A 的方法,这意味着 A.f 将调用 B.g,如果你更改方法 B.g 的名称,你的代码将按预期运行

【讨论】:

  • 有没有不改B.g名字的解决办法? A 是一个 scikit-learn 转换器,ffitgfit_transform。由于这是 scikit-learn 及其他领域的标准术语,我想避免为我的子类更改它。
  • 我认为 rdas 给出的解决方案在你的情况下会很好用
  • 在这种情况下,我的子类B 不会从A 继承所有其他属性,我将不得不以更复杂的方式访问它们。我(几乎)确信有一个更优雅的解决方案。关键点好像在super(),但是找不到解决办法。
【解决方案2】:

我没有正确理解什么?

即使在A.f 中调用了self.g(),作为self 传递的值仍然是B 的一个实例,因此此操作查找的是B.g,而不是A.g

如果你能用这个结构解释你试图解决的问题,那将会很有帮助。特别是,我不明白为什么对于任何 real-world 代码,在 B 类中 g 调用 f 会很有用,但在基类中这样做反之亦然。

【讨论】:

    【解决方案3】:

    self 绑定到调用.g()B 对象。

    尝试用组合替换继承:

    class A:
        def f(self):
            print('Method A.f was called.')
            self.g()
    
        def g(self):
            print('Method A.g was called.')
    
    class B:
        def __init__(self, a):
            self.a = a
    
        def f(self):
            print('Method B.f was called.')
            self.a.f()
    
        def g(self):
            print('Method B.g was called.')
            self.f()
    
    a = A()
    b = B(a)
    b.g()
    

    输出:

    Method B.g was called.
    Method B.f was called.
    Method A.f was called.
    Method A.g was called.
    

    【讨论】:

      猜你喜欢
      • 2014-11-15
      • 1970-01-01
      • 2011-10-06
      • 2019-12-12
      • 2020-12-05
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多