【问题标题】:Inheritance - proper way to create a new instance of a class with a class method继承 - 使用类方法创建类的新实例的正确方法
【发布时间】:2019-01-12 00:36:02
【问题描述】:

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

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

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))

如果Fox 尝试reproduce,我将有一个Animal 类型的实例而不是Fox(即使它仍然具有'red' 的颜色)。

我可以重载方法让狐狸能够繁殖:

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

但是,我必须为我定义的每一个新生物都这样做!

我如何创建一个类,我可以让我的所有生物都从中继承,所以当它们reproduce 创建同一个类的对象时?这样我就可以确定:

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

我知道我可以使用type 使reproduce 返回type(self)(self.characteristics) 或self.__class__(**self.characteristics),但它对我来说似乎不是很严重。有没有更合适的方法来做到这一点?

【问题讨论】:

  • type(self)() 非常合适,但为此,您的所有构造函数都需要相同,但事实并非如此。
  • 你说得对,我将重新提出我的问题,让覆盖成为唯一的解决方案
  • 我们需要在这里找到一个中间立场。我在下面的回答仍然回答了您更新的问题,但现在这个答案读起来很尴尬,因为您突然实现了我提到的“委托属性”选项。答案在这里仍然是一样的,但我宁愿看到你的问题回到它的起点。
  • (请注意我的reproduce() 使用self.characteristics 的方式与您使用它的方式之间的区别;您的版本会导致类型错误,因为__init__ 不接受任何超出self 的位置参数)。

标签: python python-3.x


【解决方案1】:

注意:您的问题从您的子类采用不同数量的参数的问题改变了。如果你坚持这样的设计,那么你别无选择,只能覆盖reproduce(),因为没有一致的 API 来创建“当前类”的新实例。

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

请注意,必须为每个子类编写一个新的reproduce() 方法也是一个不错的选择,因为这是委派创建专用子类的新实例的好方法。你让每个子类负责处理复制的细节。

但是,如果您不想这样做,那么您可以从子类中移除该责任并将其放在基类中,此时您如何创建实例的基本设计是那个基类的职责。

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

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

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

这完全是 Python 风格,但更多的是因为这是一个体面的 OO 设计,您可以在其中做出选择,以尽量减少子类的责任,并让基类尽可能多地进行复制。

【讨论】:

    猜你喜欢
    • 2018-05-10
    • 2016-06-06
    • 1970-01-01
    • 2011-08-24
    • 2012-10-26
    • 2020-11-13
    • 2015-10-26
    相关资源
    最近更新 更多