python中的多个构造函数调用相同的例程

时间:2013-10-10 00:24:57

标签: python oop constructor

我正在使用@classmethod编写一个包含多个构造函数的类。现在我希望__init__构造函数以及classmethod构造函数调用类的一些例程来设置初始值,然后再执行其他操作。

__init__起,这通常是以自己的方式完成的:

def __init__(self, name="", revision=None):
    self._init_attributes()

def _init_attributes(self):
    self.test = "hello"

从classmethod构造函数中,我会调用另一个classmethod,因为在我将classmethod与self一起离开之前,不会创建实例(即return cls(...))。现在,我可以将_init_attributes()方法称为

@classmethod
def from_file(cls, filename=None)
    cls._init_attributes()
    # do other stuff like reading from file
    return cls()

这实际上是有效的(在某种意义上我没有得到错误,我可以在执行c = Class.from_file()后实际看到test属性。但是,如果我理解正确,那么这将设置属性类级别,而不是在实例级别。因此,如果我使用可变对象(例如列表)初始化属性,那么此类的所有实例将使用相同的列表,而不是它们自己的实例列表。这是正确的吗?如果是这样,有没有办法在classmethods中初始化“instance”属性,或者我是否必须以这样的方式编写代码:所有属性初始化都在 init 中完成?

嗯。实际上,在写这篇文章时:我甚至可能遇到比我想象的更大的麻烦,因为从类方法返回时会调用 init ,不是吗?那么处理这种情况的正确方法是什么呢?

注意:文章[1]讨论了一个类似的问题。

1 个答案:

答案 0 :(得分:1)

是的,你正确理解事物:cls._init_attributes()将设置类属性,而不是实例属性。

同时,由您的备用构造函数构建并返回实例。在构建它和返回它之间,就可以调用_init_attributes()。换句话说:

@classmethod
def from_file(cls, filename=None)
    obj = cls()
    obj._init_attributes()
    # do other stuff like reading from file
    return obj

但是,你是对的,构建和返回实例的唯一明显方法是只调用cls(),它将调用__init__


但这很容易解决:只是让备用构造函数将一些额外的参数传递给__init__,意思是“跳过通常的初始化,我将在以后再做”。例如:

def __init__(self, name="", revision=None, _skip_default_init=False):
    # blah blah

@classmethod
def from_file(cls, filename=""):
    # blah blah setup
    obj = cls(_skip_default_init=True)
    # extra initialization work
    return obj

如果你想让它不那么明显,你可以随时取**kwargs并在方法体内查看它......但请记住,这是Python;你不能阻止人们做蠢事,你所能做的就是明白他们是愚蠢的。并且_skip_default_init应该足以处理它。


如果您真的想要,也可以覆盖__new__。除非__init__返回__new__的实例或其某些子类,否则构造对象不会调用cls。因此,您可以通过隐藏__new____init__提供一个标记,告诉其跳过obj.__class__,然后自行恢复__class__。这真的很糟糕,但可以想象是有用的。


一个更清晰的解决方案 - 但由于某种原因在Python中更不常见 - 是借用Smalltalk / ObjC的“类集群”思想:创建一个私有子类,它具有不同的__init__ { {1}}(或故意跳过它的直接基数和super),然后让基类中的备用构造函数返回该子类的实例。


或者,如果您不想致电super的唯一原因是,您可以完成同样的事情__init__会做...为什么? DRY代表“不要重复自己”,而不是“向后弯腰想办法强迫自己重复自己”,对吗?