代码之家  ›  专栏  ›  技术社区  ›  LoicM

继承-使用类方法创建类的新实例的正确方法

  •  0
  • LoicM  · 技术社区  · 6 年前

    我是上帝(或进化论,或任何你相信的东西)。我正在尝试用巨蟒创造所有的生物。

    我已经定义了一个能够“复制”的类,即能够创建一个新的自身实例(忽略它看起来更像克隆而不是复制的事实,这是一个测试版的地球):

    class Animal:
        def __init__(self, **kwargs):
             self.characteristics = kwargs
    
        def reproduce(self):
            return Animal(**self.characteristics)
    

    在基类的情况下,这很好,但是当我创建一个继承自 Animal ?

    class Fox (Animal):
        def __init__ (self, **kwargs):
            self.color = 'red'
            super().__init__(dict(self.color, **kwargs))
    

    如果A Fox 试图 reproduce ,我将有一个类型为的实例 动物 而不是 福克斯 (即使它仍然有颜色 'red' )

    我可以用超负荷的方法让狐狸能够繁殖:

    def reproduce(self):
         return Fox(self.characteristics)
    

    然而,我必须为我定义的每一个新生物做这件事!

    我怎样才能创造一个类,使我所有的生物都能从中继承,当它们 复制 是否创建了同一类的对象?所以我可以确定:

    parent = Fox()
    child = parent.reproduce()
    assert type(parent) == type(child)
    

    我知道我可以用 type 使 复制 返回 type(self)(self.characteristics) self.__class__(**self.characteristics) 但对我来说,这似乎不是很强的补药。有没有更合适的方法?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Martijn Pieters    6 年前

    注意:您将您的问题从一个子类接受不同数量参数的问题更改为另一个问题。如果你坚持这样的设计,那么你在这里别无选择,只能重写 reproduce() ,因为没有一致的API来创建“当前类”的新实例。

    如果要使类API标准化,那么还可以标准化创建新实例,此时可以编写一个 复制() 方法 type(self) 引用当前类,然后继续生成该类的新实例。

    注意要写一个新的 复制() 每个子类的方法是一个很好的选择 因为这是授权创建专门子类的新实例的好方法。你给每个子类处理复制细节的责任。

    但是如果您不想这样做,那么您可以从子类中去掉该职责,并将其放到基类中,此时基础 设计 创建实例的方式也是该基类的职责。

    当然,这两种选择之间存在着中间立场,但它们都归结为某种形式的授权。您可以让基类提供某种结构,详细说明在创建实例时应该复制哪些属性,您可以让子类实现 __copy__ or __deepcopy__ hooks 通过处理“复制” copy.copy() copy.deepcopy() 电话等

    您更新的问题结构只是该授权的另一个示例;您添加了 characteristics 字典,因此子类负责保持字典的更新,以便基类可以实现如下的复制:

    def reproduce(self):
        return type(self)(**self.characteristics)
    

    这是一个完美的蟒蛇,但更多的是因为这是一个体面的OO设计,在那里你可以选择最小化子类的责任,让基类尽可能多地进行复制。