扩展方法时将局部变量保留在范围内

Keep local variables in scope when extending a method

假设我有一个 class TT 继承自 class T 并扩展其中一种方法的行为,如下所示:

class T:
    def __init__(self, p, b):
        self.p = p
        self.b = b
        self.fun()
        
    def fun(self):
        a = self.p + self.b
        print(a)
        

class TT(T):
    def __init__(self, p, b):
        super().__init__(p, b)
        
    def fun(self):
        super().fun()
        c = self.p*self.b
        print(c)

我想要的是 TT.fun 依赖于 T.fun 中定义的变量,在此示例中为 a。想到的两个明显的事情是使 T.fun return a 或使 a 成为实例变量,但我发现两者都不令人满意。有没有办法 TT.fun 共享它扩展的方法的范围?


编辑

感谢您的回答。

为了扩展我的用例,我派生了 classes 运行 针对数据集的向量优化。父 class 在这里建议对不同的优化使用一个通用的、连贯的接口。 在要优化的 class' 函数中,一些步骤(取决于向量的当前状态)由所有子 classes 共享,这就是为什么我认为我会把它放在父方法。正如 Lagerbaer 所建议的那样,它们已经 运行 相当于“私有” compute_a() 方法;我的想法是调用此方法将结果带到父 class 的范围内,这样我就不必在单个子 class 中执行此操作。事实证明,考虑到我正在处理的子classes 数量很少,复制几行代码可能是这里最简单的事情。

关于 Nathaniel Ford 的建议,这就是为什么我觉得我最初的解决方案不令人满意的原因:

正如您所指出的,我的想法不是封装友好的;偶尔有这样的提醒也不错!

没有直接的非 hacky 方法。 (而且我什至不知道 是否 是一种 hacky 方式)。

你的提议违反了封装原则。 class 隐藏了其内部细节,只暴露了具有承诺行为的整洁界面。

继承不是违反此原则的机制。

在您的具体示例中,问题来自 T 的不良界面设计。如果 T 有一个方法 compute_a() return self.p + self.b 那么在你继承的 class 你当然可以调用 self.compute_a().

但仅当 a 不仅仅是内部实施细节时才这样做!

简短的回答是 'no',特别是因为子 class 有一个与父 class 中的函数同名的函数并不意味着这些函数共享任何事物。当您调用 super().fun() 时,您是在父 class 上调用 fun(),但这与在完全不相关的 class 上调用 fun() 相同 - 除了只要父 class 正在共享它的状态(实例变量)。

因此,子class实例访问发生在父class实例函数中的计算的唯一方法是通过正常模式:

  • 将结果保存到实例的状态(实例变量)。
  • 返回值,使 super().fun() 变为 a = super().fun()
  • 保存到其他一些更全局范围的值(不推荐)。

当您说 'neither way is satisfactory' 时,您可能应该更深入地挖掘并检查原因。有一些替代方法,例如私有方法,可以以干净的方式解决看似混乱的情况。也就是说,您的示例没有说明为什么 fun() 甚至被覆盖,或者您希望通过共享范围来完成什么。

您可以在父 class 中简单地 return 来自 fun() 的值,然后将 returned 值分配给子方法中的变量。这当然有效,但我认为这不是一个好的设计:

class T:
    def __init__(self, p, b):
        self.p = p
        self.b = b
        self.fun()
        
    def fun(self):
        a = self.p + self.b
        return a
        

class TT(T):
    def __init__(self, p, b):
        super().__init__(p, b)
        
    def fun(self):
        a = super().fun()
        c = self.p * self.b * a
        return c

t = T(2, 3)
tt = TT(2, 3)
print(t.fun())   # >> 5
print(tt.fun())  # >> 30