为什么__init __()总是在__new __()之后调用?

我只是想简化我的一个类,并已经引入了与flyweightdevise模式相同风格的一些function。

不过,我对__init__之后总是调用__init__有点困惑。 我并不期待这一点。 任何人都可以告诉我为什么发生这种情况,如何才能实现这个function呢? (除了把这个实现放到__new__里面,觉得挺__new__ )。

这是一个例子:

 class A(object): _dict = dict() def __new__(cls): if 'key' in A._dict: print "EXISTS" return A._dict['key'] else: print "NEW" return super(A, cls).__new__(cls) def __init__(self): print "INIT" A._dict['key'] = self print "" a1 = A() a2 = A() a3 = A() 

输出:

 NEW INIT EXISTS INIT EXISTS INIT 

为什么?

当你需要控制新实例的创build时使用__new__ 。 当需要控制新实例的初始化时,使用__init__

__new__是实例创build的第一步。 它被称为第一个,并负责返回您的类的新实例。 相反, __init__不返回任何东西; 它只是在创build实例后才负责初始化。

一般来说,除非你inheritance了像str,int,unicode或tuple这样的不可变types,否则你不需要重载__new__

来自: http : //mail.python.org/pipermail/tutor/2008-April/061426.html

你应该考虑你所要做的通常是用一个工厂来完成,这是最好的方法。 使用__new__不是一个很好的清洁解决scheme,所以请考虑工厂的使用情况。 在这里你有一个很好的工厂的例子 。

__new__是静态类方法,而__init__是实例方法。 __new__必须首先创build实例,所以__init__可以初始化它。 请注意, __init__self作为参数。 直到你创build实例,没有self

现在,我收集,你正在尝试在Python中实现单例模式 。 有几种方法可以做到这一点。

另外,从Python 2.6开始,您可以使用类装饰器 。

 def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... 

在大多数着名的OO语言中,像SomeClass(arg1, arg2)这样的expression式将分配一个新的实例,初始化实例的属性,然后返回它。

在大多数着名的OO语言中,可以通过定义一个构造函数为每个类定制“初始化实例的属性”部分,这个构造函数基本上只是一个在新实例上运行的代码块(使用提供给构造函数expression式的参数)设置任何最初的条件是需要的。 在Python中,这对应于类__init__方法。

Python的__new__是“分配新实例”部分的类定制而已。 这当然可以让你做不寻常的事情,例如返回一个现有的实例,而不是分配一个新的实例。 所以在Python中,我们不应该认为这部分是必然涉及分配的; 所有我们需要的是__new__从某处出现一个合适的实例。

但是它仍然只有一半的工作,Python系统无法知道有时候你想要运行另一半的工作( __init__ ),有时候你不需要。 如果你想要这样的行为,你必须明确地说出来。

通常情况下,你可以重构,所以你只需要__new__ ,所以你不需要__new__ ,或者__init__在已经初始化的对象上performance不同。 但是,如果你真的想,Python实际上允许你重新定义“工作”,所以SomeClass(arg1, arg2)不一定会调用__new__后面跟__init__ 。 为此,您需要创build一个元类,并定义它的__call__方法。

元类只是一个类的类。 而一个类的__call__方法控制了当你调用类的实例时会发生什么。 所以一个元类__call__方法控制了当你调用一个类时会发生什么。 即它允许您从头到尾重新定义实例创build机制 。 这是您可以最优雅地实现完全非标准的实例创build过程(如单例模式)的级别。 事实上,只需less于10行的代码,你就可以实现一个Singleton元类,它甚至不需要你用__new__来完成任何 __metaclass__ = Singleton ,只需要添加__metaclass__ = Singleton ,就可以把任何其他正常的类变成单__metaclass__ = Singleton

 class Singleton(type): def __init__(self, *args, **kwargs): super(Singleton, self).__init__(*args, **kwargs) self.__instance = None def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(Singleton, self).__call__(*args, **kwargs) return self.__instance 

然而,这可能是更深的魔力比真正保证这种情况!

引用文档 :

典型实现通过使用具有适当参数的“super(currentclass,cls).__new__(cls [,…])”调用超类的__new__()方法,然后根据需要修改新创build的实例来创build类的新实例在返回之前。

如果__new __()没有返回一个cls实例,那么新实例的__init __()方法将不会被调用。

__new __()主要用于允许不可变types的子类(如int,str或tuple)自定义实例创build。

我意识到这个问题是相当古老的,但我也有类似的问题。 以下做了我想要的:

 class Agent(object): _agents = dict() def __new__(cls, *p): number = p[0] if not number in cls._agents: cls._agents[number] = object.__new__(cls) return cls._agents[number] def __init__(self, number): self.number = number def __eq__(self, rhs): return self.number == rhs.number Agent("a") is Agent("a") == True 

我用这个页面作为资源http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html

我认为这个问题的简单答案是,如果__new__返回一个与类相同types的值, __init__函数将会执行,否则不会。 在这种情况下,您的代码会返回与cls相同的类A._dict('key') ,所以__init__将被执行。

__new__返回同一个类的实例时, __init__会在返回的对象上运行。 即你不能使用__new__来防止__init__被运行。 即使你从__new__返回以前创build的对象,它将会是__init__被一次又一次初始化的double(triple等)。

这里是对单例模式的通用方法,它扩展了上面的vartec答案并修复了它:

 def SingletonClass(cls): class Single(cls): __doc__ = cls.__doc__ _initialized = False _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Single, cls).__new__(cls, *args, **kwargs) return cls._instance def __init__(self, *args, **kwargs): if self._initialized: return super(Single, self).__init__(*args, **kwargs) self.__class__._initialized = True # Its crucial to set this variable on the class! return Single 

完整的故事在这里 。

另一种实际上涉及__new__是使用类方法:

 class Singleton(object): __initialized = False def __new__(cls, *args, **kwargs): if not cls.__initialized: cls.__init__(*args, **kwargs) cls.__initialized = True return cls class MyClass(Singleton): @classmethod def __init__(cls, x, y): print "init is here" @classmethod def do(cls): print "doing stuff" 

请注意,使用这种方法,您需要使用@classmethod修饰所有方法,因为您永远不会使用任何MyClass实例。

 class M(type): _dict = {} def __call__(cls, key): if key in cls._dict: print 'EXISTS' return cls._dict[key] else: print 'NEW' instance = super(M, cls).__call__(key) cls._dict[key] = instance return instance class A(object): __metaclass__ = M def __init__(self, key): print 'INIT' self.key = key print a1 = A('aaa') a2 = A('bbb') a3 = A('aaa') 

输出:

 NEW INIT NEW INIT EXISTS 

NB作为一个副作用, M._dict属性可以自动地从A作为A._dict访问,所以注意不要随意覆盖它。

__new__应该返回一个新的空白的类实例。 然后调用__init__来初始化那个实例。 在__new__的“NEW”情况下,你不会调用__init__,所以它正在被调用。 调用__new__的代码不会跟踪__init__是否在特定的实例上被调用,也不应该这样做,因为您在这里做的事情非常不寻常。

你可以在__init__函数中添加一个属性来指示它已经被初始化了。 检查__init__中是否存在该属性,如果已经存在,则不要继续。

深入挖掘!

CPython中generics类的types是type ,它的基类是Object (除非你显式定义了另一个基类,如元类)。 低级调用的顺序可以在这里find。 调用的第一个方法是type_call ,然后调用tp_new然后调用tp_init

这里有趣的部分是, tp_new将调用Object的(基类)新方法object_new ,它执行一个tp_allocPyType_GenericAlloc )为对象分配内存:)

此时,对象在内存中创build,然后调用__init__方法。 如果__init__没有在你的类中实现,那么object_init被调用,它什么都不做:)

然后type_call只是返回绑定到你的variables的对象。

参考这个文档 :

在inheritance不可变的内置types(如数字和string)时,偶尔会出现其他情况,静态方法new派上用场。 new是实例构造的第一步,在init之前调用。

新的方法是以类作为第一个参数来调用的; 其职责是返回该类的新实例。

将它与init进行比较:使用实例作为第一个参数调用init ,并且不返回任何内容; 它的职责是初始化实例。

有些情况下,不用调用init就可以创build一个新的实例(例如,当实例从一个pickle中加载时)。 如果不调用new,就没有办法创build一个新的实例(尽pipe在某些情况下,你可以通过调用一个的基类来实现)。

关于你想达到什么目的,还有关于Singleton模式的相同的文档信息

 class Singleton(object): def __new__(cls, *args, **kwds): it = cls.__dict__.get("__it__") if it is not None: return it cls.__it__ = it = object.__new__(cls) it.init(*args, **kwds) return it def init(self, *args, **kwds): pass 

您也可以使用装饰器从PEP 318使用此实现

 def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... 

我们应该将init看作传统OO语言中的简单构造函数。 例如,如果您熟悉Java或C ++,则构造函数将隐式地传递一个指向其自己的实例的指针。 在Java的情况下,它是“这个”variables。 如果要检查为Java生成的字节代码,则会注意到两个调用。 第一个调用是“新”方法,然后下一个调用是init方法(这是对用户定义的构造函数的实际调用)。 这两个步骤过程可以在调用该类的构造方法之前创build实际的实例,这只是该实例的另一种方法。

现在,在Python的情况下, 新增function是用户可以访问的。 由于Java的types性质,Java不提供这种灵活性。 如果一个语言提供了这个工具,那么new的实现者可以在返回实例之前用这个方法做很多事情,包括在某些情况下创build一个不相关对象的全新实例。 而且,对于Python中的不可变types,这种方法也适用。

__init____new__之后被调用,所以当你在一个子类中覆盖它时,你添加的代码仍然会被调用。

如果你试图给一个已经拥有__new__的类子类, __new__不知道这个的类可能会先调用__init__并将调用转发给子类__init__ 。 这个在__new__之后调用__init__ __new__有助于按预期工作。

__init__仍然需要允许超类__new__所需的任何参数,但是如果不这样做,通常会产生一个明确的运行时错误。 而__new__应该明确地允许*args和'** kw',以表明扩展是可以的。

由于原始海报描述的行为,在相同级别的inheritance中同时拥有__new____init__通常是不好的forms。

对@AntonyHatchkins的更新回答,你可能需要为每个元types的一个单独的实例字典,这意味着你应该在元类中有一个__init__方法用这个字典初始化你的类对象,而不是在所有的类中使它成为全局的。

 class MetaQuasiSingleton(type): def __init__(cls, name, bases, attibutes): cls._dict = {} def __call__(cls, key): if key in cls._dict: print('EXISTS') instance = cls._dict[key] else: print('NEW') instance = super().__call__(key) cls._dict[key] = instance return instance class A(metaclass=MetaQuasiSingleton): def __init__(self, key): print 'INIT' self.key = key print() 

我已经提前使用__init__方法更新了原始代码,并将语法更改为Python 3符号(no-arg在类参数中调用super和metaclass,而不是作为属性)。

无论哪种方式,这里的重要一点是,如果find了密钥,则类初始化程序( __call__方法)将不会执行__new____init__ 。 这比使用__new__要干净得多,如果你想跳过缺省的__init__步骤,需要标记对象。

不过,我对__init__之后总是调用__init__有点困惑。

除了这样做以外,没有什么其他原因。 __new__没有初始化类的责任,还有一些方法( __call__ ,可能 – 我不知道)。

我并不期待这一点。 任何人都可以告诉我为什么发生这种情况,如何实现这个function呢? (除了把这个实现放到__new__里面感觉很__new__ )。

如果__init__已经被初始化了,你可以不做任何事情,或者你可以用一个新的__call__编写一个新的元类,它只在新实例上调用__init__ ,否则返回__new__(...)