扩展方法时将局部变量保留在范围内
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
假设我有一个 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