有没有办法实例化类,而不调用__init__? [英] Is there a way to instantiate a class without calling __init__?

查看:344
本文介绍了有没有办法实例化类,而不调用__init__?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法绕过python中的类的构造函数 __ init __



p>

  class A(object):
def __init __(self):
printFAILURE

def Print(self):
printYEHAA

喜欢创建 A 的实例。它可能看起来像这样,但是这种语法是不正确的。

  a = A 
a.Print b $ b

Thx提前为您提供帮助。



编辑:



一个更复杂的例子:



假设我有一个对象 C ,它的目的是存储一个单一的参数,并做一些计算。然而,该参数不是这样传递的,而是嵌入在巨大的参数文件中。它可能看起来像这样:

  class C(object):
def __init __(self,ParameterFile):
self._Parameter = self._ExtractParamterFile(ParameterFile)
def _ExtractParamterFile(self,ParameterFile):
#does一些复杂的魔法来提取正确的参数
return the_extracted_pa​​rameter

现在我想转储并加载该对象的实例 C 。但是,当我加载这个对象时,我只有单个变量 self._Parameter ,我不能调用构造函数,因为它期待参数文件。

  @staticmethod 
def Load(file):
f = open(file,rb)
oldObject = pickle.load(f)
f.close()

#somehow创建newObject而不调用__init__
newObject._Parameter = oldObject._Parameter
return newObject

换句话说,不能在不传递参数文件的情况下创建实例。然而,在我的真实的情况下,它不是一个参数文件,但一些巨大的数据垃圾,我肯定不想携带在内存中,甚至存储到光盘。



因为我想从方法 Load 返回 C 的实例,我不知何故必须调用构造函数。



OLD编辑:



一个更复杂的例子,说明为什么我要问问题:

  class B(object):
def __init __(self,name,data):
self._Name = name
#do某些数据,但不保存数据在变量

@staticmethod
def Load(self,file,newName):
f = open(file,rb)
s = pickle.load(f)
f.close()

newS = B b $ b newS._Name = newName
return newS

正如你所看到的, code> data 不存储在类变量中,我不能将其传递给 __ init __ 。当然我可以简单地存储它,但如果数据是一个巨大的对象,我不想在内存中一直携带或甚至保存到光盘?

通过调用 __ new __ 可以绕过 __ init __ $ c>直接。然后,您可以创建给定类型的对象,并调用 __ init __ 的替代方法。这是 pickle 会做的。



但是,首先我要强调的是, 不应 无论你想要实现什么,有更好的方法来做,其中一些已经提到在其他答案。特别是,跳过调用 __ init __ 是一个不好的主意。



创建对象时,或多或少会发生这种情况:

  a = A .__ new __(A,* args,** kwargs)
a .__ init __(* args,** kwargs)

您可以跳过第二步。



这里是不应该 __ init __ 的目的是初始化对象,填写所有字段,并确保 __ init __ 父类的方法也被调用。使用 pickle 它是一个异常,因为它试图存储所有与对象相关的数据(包括为 对象),所以任何由 __ init __ 设置的上一次将被pickle恢复,没有必要再次调用它。



如果跳过 __ init __ 并使用替代的初始值设定器,将是两个实例变量被填充的地方,很容易在其中一个初始化器中错过其中一个,或者意外地使两个填充字段的行为不同。这提供了微小的错误的可能性,这不是微不足道的跟踪(你必须知道哪个初始化程序被调用),代码将更难以维护。更不用说,如果你使用继承,你会在更大的麻烦 - 问题将继承的继承链,因为你必须使用这个替代的初始值设置链上的任何地方。



也可以这样做,你或多或少地重写Python的实例创建和自己。 Python已经为你做了很好,没有必要去重塑它,它会混淆使用你的代码的人。



这里是最好的做法, / strong>使用一个单独的 __ init __ 方法,该方法将被正确初始化所有实例变量的类的所有可能的实例化调用。对于不同的初始化模式,使用以下两种方法之一:


  1. 支持 __ init __
  2. 创建几个类方法作为替代构造函数。确保他们都以正常方式创建类的实例(即调用 __ init __ ),如Roman Bodnarchuk所示,同时执行额外的工作或任何。如果他们将所有的数据传递给类(和 __ init __ 处理它)是最好的,但如果这是不可能或不方便,你可以在实例创建后设置一些实例变量, __ init __ 完成初始化。

如果 __ init __ 有一个可选步骤(例如,处理 data 参数,虽然你必须更具体),你可以使它成为一个可选参数或者使用正常的方法来处理...或两者。


Is there a way to circumvent the constructor __init__ of a class in python?

Example:

class A(object):    
    def __init__(self):
        print "FAILURE"

    def Print(self):
        print "YEHAA"

Now I would like to create an instance of A. It could look like this, however this syntax is not correct.

a = A
a.Print()

Thx in advance for your help.

EDIT:

An even more complex example:

Suppose I have an object C, which purpose it is to store one single parameter and do some computations with it. The parameter, however, is not passed as such but it is embedded in a huge parameter file. It could look something like this:

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

Now I would like to dump and load an instance of that object C. However, when I load this object, I only have the single variable self._Parameter and I cannot call the constructor, because it is expecting the parameter file.

    @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

In other words, it is not possible to create an instance without passing the parameter file. In my "real" case, however, it is not a parameter file but some huge junk of data I certainly not want to carry around in memory or even store it to disc.

And since I want to return an instance of C from the method Load I do somehow have to call the constructor.

OLD EDIT:

A more complex example, which explains why I am asking the question:

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

As you can see, since data is not stored in a class variable I cannot pass it to __init__. Of course I could simply store it, but what if the data is a huge object, which I do not want to carry around in memory all the time or even save it to disc?

解决方案

You can circumvent __init__ by calling __new__ directly. Then you can create a object of the given type and call an alternative method for __init__. This is something that pickle would do.

However, first I'd like to stress very much that it is something that you shouldn't do and whatever you're trying to achieve, there are better ways to do it, some of which have been mentioned in the other answers. In particular, it's a bad idea to skip calling __init__.

When objects are created, more or less this happens:

a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)

You could skip the second step.

Here's why you shouldn't do this: The purpose of __init__ is to initialize the object, fill in all the fields and ensure that the __init__ methods of the parent classes are also called. With pickle it is an exception because it tries to store all the data associated with the object (including any fields/instance variables that are set for the object), and so anything that was set by __init__ the previous time would be restored by pickle, there's no need to call it again.

If you skip __init__ and use an alternative initializer, you'd have a sort of a code duplication - there would be two places where the instance variables are filled in, and it's easy to miss one of them in one of the initializers or accidentally make the two fill the fields act differently. This gives the possibility of subtle bugs that aren't that trivial to trace (you'd have to know which initializer was called), and the code will be more difficult to maintain. Not to mention that you'd be in an even bigger mess if you're using inheritance - the problems will go up the inheritance chain, because you'd have to use this alternative initializer everywhere up the chain.

Also by doing so you'd be more or less overriding Python's instance creation and making your own. Python already does that for you pretty well, no need to go reinventing it and it will confuse people using your code.

Here's what to best do instead: Use a single __init__ method that is to be called for all possible instantiations of the class that initializes all instance variables properly. For different modes of initialization use either of the two approaches:

  1. Support different signatures for __init__ that handle your cases by using optional arguments.
  2. Create several class methods that serve as alternative constructors. Make sure they all create instances of the class in the normal way (i.e. calling __init__), as shown by Roman Bodnarchuk, while performing additional work or whatever. It's best if they pass all the data to the class (and __init__ handles it), but if that's impossible or inconvenient, you can set some instance variables after the instance was created and __init__ is done initializing.

If __init__ has an optional step (e.g. like processing that data argument, although you'd have to be more specific), you can either make it an optional argument or make a normal method that does the processing... or both.

这篇关于有没有办法实例化类,而不调用__init__?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆