【问题标题】:Inheritance : Base class method which returns an instance of itself继承:返回自身实例的基类方法
【发布时间】:2014-03-18 23:27:32
【问题描述】:

我的基类有一个返回自身实例的方法。当我写我的子类时,有没有什么办法可以让这个实例成为我的子类的实例而不是基类,而不需要修改基类的代码或者将整个基类方法重写到我的子类方法中?

例子:

class A:
    def __init__(self,x):
        self.x = x
    def add(self):
        self.x += 2
    def new(self,z):
        n = A(z)
        return n

class B(A):
    def __init__self():
        A.__init__(self,x)

如果我这样做的话:

a = B(10)
b = a.new(4)

那么 b 将是 A 的一个实例,而不是我想要的 B 的一个实例。 在这个简单的示例中,我可以只覆盖 B 类中的方法,但在我的程序中我不想这样做,它只会破坏可移植性,因为我无法控制基类,因为它是另一个包的一部分。

有什么办法吗?

【问题讨论】:

    标签: python class inheritance instance subclass


    【解决方案1】:

    使其成为类方法:

    @classmethod
    def new(cls, z):
        return cls(z)
    

    【讨论】:

    • 不能,我说过不能修改Base类的代码:(
    • 哦,抱歉,没发现。那么:没有。
    【解决方案2】:

    理想情况下,而不是:

    def new(self,z):
        n = A(z)
        return n
    

    你会有:

    def new(self, z):
        n = self.__class__(z)
        return n
    

    这样,您将使用调用方法的实例中的类,而不是硬编码要创建新实例的类。

    然而,既然你提到你不能修改基类,你有两个选择:

    1. 重写派生类中的方法
    2. 猴子补丁基类
    3. 请求维护基类的人为您进行此更改

    您说过不想覆盖它,因为它不利于可移植性。我认为这不是真的——如果基类可能会被更新,以至于它的公共 API 的行为发生变化,那么它已经不利于可移植性,因为谁知道它可能会引入哪些破坏性变化。如果行为要保持一致(即使实现发生变化),覆盖应该是安全的。

    另一个选项是猴子补丁基类。这将与在基类中覆盖相同的问题,不同之处在于其他子类也会获得该行为 - 而不仅仅是从 B 继承的那些。

    你会像这样(在类定义之外)进行猴子补丁:

    def new_new(self, z):
        n = self.__class__(z)
        return n
    
    A.new = new_new
    

    【讨论】:

    • 我会的,不幸的是,正如我所说,我无法控制基类,所以我无法重写它:(
    • 我已经更新了我的答案,但我认为我们需要解释为什么在你的情况下覆盖会不利于可移植性,因为我只是在这里猜测。
    • 好吧,如果基类中的方法在新版本中发生更改,那将是一团糟,因为我的覆盖方法将过时。这使得我的覆盖方法链接到基类模块的特定版本。因此对便携性不利。这就是为什么我想知道是否有任何方法可以在不弄乱方法本身的情况下做到这一点,但从你所说的来看这是不可能的。
    • @Nolhian 如果基类方法发生变化,依赖该基类的所有地方 是否也会变得一团糟?
    • 如果只是方法中的更新不影响结果,比如安全更新、捕获附加异常等,那么依赖基类的任何地方都不会乱七八糟.只是我的代码会过时。
    【解决方案3】:

    使用__class__:

    n = self.__class__(z)
    return n
    

    ...

    @jonrsharpe 的回答更好

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      相关资源
      最近更新 更多