有没有办法绕过__init__python中的类的构造函数?
__init__
例:
class A(object): def __init__(self): print "FAILURE" def Print(self): print "YEHAA"
现在,我想创建一个实例A。看起来可能像这样,但是这种语法不正确。
A
a = A a.Print()
编辑:
一个更复杂的示例:
假设我有一个对象C,目的是存储一个参数并对其进行一些计算。但是,该参数并未按原样传递,而是被嵌入到巨大的参数文件中。它可能看起来像这样:
C
class C(object): def __init__(self, ParameterFile): self._Parameter = self._ExtractParamterFile(ParameterFile) def _ExtractParamterFile(self, ParameterFile): #does some complex magic to extract the right parameter return the_extracted_parameter
现在,我想转储并加载该对象的实例C。但是,在加载该对象时,我只有一个变量,self._Parameter并且无法调用构造函数,因为它需要参数文件。
self._Parameter
@staticmethod def Load(file): f = open(file, "rb") oldObject = pickle.load(f) f.close() #somehow create newObject without calling __init__ newObject._Parameter = oldObject._Parameter return newObject
换句话说,在不传递参数文件的情况下无法创建实例。但是,在我的“真实”情况下,它不是参数文件,而是一些巨大的数据,我当然不希望在内存中随身携带,甚至不希望将其存储到磁盘上。
而且由于我想C从方法中返回一个实例,所以Load我不得不以某种方式调用构造函数。
Load
旧编辑:
一个更复杂的示例,它解释了 为什么 我要问这个问题:
class B(object): def __init__(self, name, data): self._Name = name #do something with data, but do NOT save data in a variable @staticmethod def Load(self, file, newName): f = open(file, "rb") s = pickle.load(f) f.close() newS = B(???) newS._Name = newName return newS
如您所见,由于data未存储在类变量中,因此无法将其传递给__init__。当然,我可以简单地存储它,但是如果数据是一个巨大的对象,我不想一直将其存储在内存中,甚至不想将其保存到磁盘上怎么办?
data
您 可以__init__通过__new__直接致电 来 规避。然后,您可以创建给定类型的对象,并为调用替代方法__init__。这是pickle可以做到的。
__new__
pickle
但是,首先,我非常想强调一点,这是您 不应该 做的事情,无论您要达到什么目的,都有更好的方法可以做到,其中一些已在其他答案中提到。特别是,跳过call是一个 坏 主意__init__。
创建对象时,或多或少会发生这种情况:
a = A.__new__(A, *args, **kwargs) a.__init__(*args, **kwargs)
您可以跳过第二步。
这就是为什么您 不应该这样 做的原因:的目的__init__是初始化对象,填写所有字段并确保__init__还调用父类的方法。有了pickle它是一个例外,因为它尝试存储与该对象关联的所有数据(包括为该对象设置的 任何 字段/实例变量),因此,__init__上次设置的任何内容都将由pickle还原,没有需要再次调用它。
如果跳过__init__并使用替代的初始化程序,则会有某种形式的代码重复- 实例变量将在两个位置填充,并且很容易在其中一个初始化程序中错过其中一个,或者不小心使其中一个两个填充字段的行为不同。这样就可以发现难以跟踪的细微错误(您必须 知道 调用了哪个初始化程序),并且代码将更难以维护。更不用说如果您使用继承会陷入更大的混乱- 问题将在继承链中蔓延,因为您必须在链的各处使用此替代初始化器。
通过这样做,您或多或少会覆盖Python的实例创建并自行创建。Python已经为您很好地做到了这一点,无需重新发明它,它会使使用您的代码的人们感到困惑。
最好的替代__init__方法是:对于将所有实例变量正确初始化的类的所有可能实例,请使用单个方法。对于不同的初始化模式,请使用以下两种方法之一:
如果__init__具有可选步骤(例如,像处理该data参数那样,尽管您必须更具体一些),则可以将其设为可选参数,也可以使之成为执行该处理的常规方法…或同时执行两者。