python - 继承 - 使用类方法创建类的新实例的正确方法
问题描述
我是上帝(或进化论,或任何你相信的东西)。我正在尝试用 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))
如果 aFox
尝试reproduce
,我将有一个 type 的实例Animal
而不是Fox
(即使它仍然有 color 'red'
)。
我可以重载狐狸能够复制的方法:
def reproduce(self):
return Fox(self.characteristics)
但是,我必须为我定义的每一个新生物都这样做!
我如何创建一个可以让我的所有生物都继承的类,以便在reproduce
创建同一类的对象时?这样我就可以确定:
parent = Fox()
child = parent.reproduce()
assert type(parent) == type(child)
我知道我可以使用type
return reproduce
or type(self)(self.characteristics)
,self.__class__(**self.characteristics)
但对我来说似乎不是很强烈。有没有更合适的方法来做到这一点?
解决方案
注意:您将问题从您的子类采用不同数量的参数的问题改变了。如果你坚持这样的设计,那么你别无选择,只能覆盖reproduce()
,因为没有一致的 API 来创建“当前类”的新实例。
如果您要标准化您的类 API,那么您还可以标准化创建新实例,此时您可以编写一个reproduce()
方法type(self)
来引用当前类,然后继续创建该类的新实例。
请注意,必须为每个子类编写一个新方法也是reproduce()
一个不错的选择,因为这是委派创建专用子类的新实例的好方法。您赋予每个子类处理复制细节的责任。
但是,如果您不想这样做,那么您可以从子类中删除该责任并将其放在基类中,此时您如何创建实例的基本设计也是该基类的责任。
当然,这两个选项之间存在中间立场,但所有这些都归结为某种形式的授权。您可以让基类提供某种结构,详细说明在创建实例时应该复制哪些属性,您可以让子类实现__copy__
or__deepcopy__
挂钩以通过copy.copy()
orcopy.deepcopy()
调用处理“复制”等。
您更新的问题结构只是该授权的另一个示例;您添加了一个characteristics
字典,因此子类负责保持该字典更新,以便基类可以将复制实现为:
def reproduce(self):
return type(self)(**self.characteristics)
这完全是 Pythonic,但更多的是因为这是一个体面的 OO 设计,您已经做出选择,以尽量减少子类负责的内容,并让基类尽可能多地进行复制。
推荐阅读
- c# - 安装程序语言资源未生成 C#
- mercurial - 'hg add' 会忽略 '.hgignore' 吗?
- python - 使用 csv 文件创建嵌套字典
- sql - 找出两张桌子之间的利润
- javascript - JavaScript - 从多个数组中创建对象
- python - 删除未使用的 SQLAlchemy 方言和测试?
- python - 树莓派添加事件。运行时错误:添加边缘检测失败
- firefox-addon-webextensions - 访问浏览器扩展存储是否有任何限制?
- javascript - 使用 jQuery 创建上/下滑动或推送效果
- python - 如何在python中使用pyqt5将QSlider添加到主窗口的工具栏