Is there a way to instantiate a class without calling __init__?
有没有一种方法可以绕过python中类的构造函数
例子:
1 2 3 4 5 6 | class A(object): def __init__(self): print"FAILURE" def Print(self): print"YEHAA" |
现在我想创建一个
1 2 | a = A a.Print() |
编辑:
更复杂的例子:
假设我有一个对象
1 2 3 4 5 6 | 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 |
现在,我想转储并加载该对象的一个实例
1 2 3 4 5 6 7 8 9 | @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 |
换句话说,不传递参数文件就无法创建实例。然而,在我的"真实"案例中,它不是一个参数文件,而是一些巨大的数据垃圾,我肯定不想在内存中携带,甚至不想将其存储到光盘上。
因为我想从方法
旧编辑:
一个更复杂的例子,解释了我为什么要问这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
如您所见,由于
你可以直接打电话给
然而,首先,我想强调的是,这是你不应该做的事情,无论你想做什么,都有更好的方法,其中一些方法在其他答案中已经提到。尤其是,不打电话给
创建对象时,或多或少会发生以下情况:
1 2 | a = A.__new__(A, *args, **kwargs) a.__init__(*args, **kwargs) |
你可以跳过第二步。
这就是您不应该这样做的原因:
如果跳过
此外,这样做或多或少会覆盖Python的实例创建并创建自己的实例。Python已经很好地为您做到了这一点,不需要重新设计它,它会使使用您的代码的人感到困惑。
下面是最好的替代方法:使用一个单独的
如果
使用
1 2 3 4 5 6 7 8 9 10 11 12 | class B(object): def __init__(self, name, data): self._Name = name #store data @classmethod def Load(cls, file, newName): f = open(file,"rb") s = pickle.load(f) f.close() return cls(newName, s) |
所以你可以这样做:
1 | loaded_obj = B.Load('filename.txt', 'foo') |
编辑:
无论如何,如果您仍然想省略
1 2 3 4 5 6 7 8 9 10 | >>> class A(object): ... def __init__(self): ... print '__init__' ... >>> A() __init__ <__main__.A object at 0x800f1f710> >>> a = A.__new__(A) >>> a <__main__.A object at 0x800f1fd50> |
从字面上看,我会使用元类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MetaSkipInit(type): def __call__(cls): return cls.__new__(cls) class B(object): __metaclass__ = MetaSkipInit def __init__(self): print"FAILURE" def Print(self): print"YEHAA" b = B() b.Print() |
这对于在不污染参数列表的情况下复制构造函数很有用。但要正确地做到这一点,比我提议的黑客要更加努力和关心。
不是真的。
1 2 3 4 5 | def emptyinit(self): pass A.__init__ = emptyinit a = A() a.Print() |
这将动态地从类中切换出哪个
您还可以对它进行子类化,以创建自己的类,该类执行所有相同的操作,除了重写
但是,您可能只希望从类中调用方法而不实例化对象。如果是这样的话,您应该研究@classmethod和@staticmethod修饰符。他们只允许这种行为。
在代码中,您已经放置了@staticmethod decorator,它不接受
1 2 3 4 5 6 | @classmethod def Load(cls, file, newName): # Get the data data = getdata() # Create an instance of B with the data return cls.B(newName, data) |
最新消息:Rosh出色的回答指出,通过实现
我在读python的食谱,有一节讨论这个:这个例子是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> class A: def __init__(self,a): self.a = a >>> test = A('a') >>> test.a 'a' >>> test_noinit = A.__new__(A) >>> test_noinit.a Traceback (most recent call last): File"", line 1, in test_noinit.a AttributeError: 'A' object has no attribute 'a' >>> |
不过,我认为这只适用于Python3。下面是在2.7下运行
1 2 3 4 5 6 7 8 9 10 11 12 | >>> class A: def __init__(self,a): self.a = a >>> test = A.__new__(A) Traceback (most recent call last): File"", line 1, in test = A.__new__(A) AttributeError: class A has no attribute '__new__' >>> |
正如我在评论中所说,您可以更改您的
1 2 | def __init__(self, p0, p1, p2): # some logic |
将成为:
1 2 3 | def __init__(self, p0=None, p1=None, p2=None): if p0 and p1 and p2: # some logic |
或:
1 2 3 | def __init__(self, p0=None, p1=None, p2=None, init=True): if init: # some logic |