关于python:为什么总是在__new__()之后调用__init__()

Why is __init__() always called after __new__()?

我只是在尝试简化我的一个类,并以与flyweight设计模式相同的风格引入了一些功能。

不过,我有点困惑,为什么__init__总是在__new__之后调用。我没想到会这样。有人能告诉我为什么会发生这种情况,以及我如何以其他方式实现这种功能吗?(除了将实现放在__new__中,这让人感觉很不舒服。)

下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()

输出:

1
2
3
4
5
6
7
8
NEW
INIT

EXISTS
INIT

EXISTS
INIT

为什么?


Use __new__ when you need to control
the creation of a new instance. Use
__init__ when you need to control initialization of a new instance.

__new__ is the first step of instance creation. It's called first, and is
responsible for returning a new
instance of your class. In contrast,
__init__ doesn't return anything; it's only responsible for initializing the
instance after it's been created.

In general, you shouldn't need to
override __new__ unless you're
subclassing an immutable type like
str, int, unicode or tuple.

发件人:http://mail.python.org/pipermail/tutor/2008-april/061426.html

你应该考虑一下,你想做的事情通常都是在工厂里完成的,这是最好的方法。使用"新"不是一个好的清洁解决方案,因此请考虑使用工厂。这里有一个很好的工厂例子。


__new__是静态类方法,__init__是实例方法。__new__必须先创建实例,所以__init__可以初始化它。注意,__init__self为参数。在创建实例之前,没有self

现在,我了解到,您正试图在Python中实现单例模式。有几种方法可以做到这一点。

另外,从Python2.6开始,您可以使用类修饰符。

1
2
3
4
5
6
7
8
9
10
11
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)这样的表达式将分配一个新实例,初始化实例的属性,然后返回它。

在大多数著名的OO语言中,"初始化实例的属性"部分可以通过定义一个构造函数为每个类定制,它基本上只是一个代码块,在新实例上操作(使用提供给构造函数表达式的参数),以设置所需的任何初始条件。在python中,这对应于类'__init__方法。

python的__new__只不过是"分配新实例"部分的类内定制。当然,这允许您做一些不寻常的事情,比如返回一个现有的实例,而不是分配一个新的实例。所以在python中,我们不应该真的认为这部分涉及到分配;我们所需要的只是__new__从某个地方提出了一个合适的实例。

但它仍然只是作业的一半,而且Python系统无法知道,有时您希望在之后运行作业的另一半(__init__),有时您不想运行。如果您希望这种行为,您必须如此明确地说。

通常,您可以重构,这样您只需要__new__,或者不需要__new__,或者使__init__在已经初始化的对象上的行为不同。但是如果您真的想这样做,python确实允许您重新定义"作业",这样SomeClass(arg1, arg2)就不必调用__new__,后面跟着__init__。为此,您需要创建一个元类,并定义它的__call__方法。

元类只是类的一个类。类"EDOCX1"〔11〕方法控制调用该类的实例时会发生什么。因此,元类"EDOCX1"(11)方法控制调用类时会发生什么;即,它允许您从头到尾重新定义实例创建机制。这是您可以最优雅地实现完全非标准实例创建过程(如单例模式)的级别。事实上,如果代码行少于10行,您就可以实现一个Singleton元类,这样就根本不需要您使用__new__进行futz操作,并且只需添加__metaclass__ = Singleton,就可以将任何其他正常类转换为单例类!

1
2
3
4
5
6
7
8
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

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


引用文档:

Typical implementations create a new instance of the class by invoking
the superclass's __new__() method using"super(currentclass,
cls).__new__(cls[, ...])"with appropriate arguments and then
modifying the newly-created instance as necessary before returning it.

...

If __new__() does not return an instance of cls, then the new
instance's __init__() method will not be invoked.

__new__() is intended mainly to allow subclasses of immutable
types (like int, str, or tuple) to customize instance creation.


我知道这个问题很古老,但我也有类似的问题。以下是我想要的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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__返回的值与类的类型相同,则执行__init__函数,否则不会执行。在这种情况下,您的代码返回的A._dict('key')cls的类相同,因此执行__init__


__new__返回同一类的实例时,随后对返回的对象运行__init__。即不能使用__new__来防止__init__运行。即使您从__new__返回先前创建的对象,它也会被__init__一次又一次地初始化为double(triple等…)。

下面是对singleton模式的通用方法,它扩展了上面的vartec答案并修复了它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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__的另一种方法是使用类方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的任何实际实例。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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')

输出:

1
2
3
4
5
6
7
NEW
INIT

NEW
INIT

EXISTS

注意,作为副作用,M._dict属性自动从A作为A._dict可访问,因此注意不要意外地覆盖它。


如果更新@antonyhatchkins的答案,您可能需要为元类型的每个类提供一个单独的实例字典,这意味着您应该在元类中有一个__init__方法来用该字典初始化类对象,而不是使它在所有类中都是全局的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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表示法(在类参数中没有对super和元类的arg调用,而不是作为属性)。

不管怎样,这里重要的一点是,如果找到了键,类初始值设定项(__call__方法)将不会执行__new____init__。这比使用__new__要干净得多,如果要跳过默认的__init__步骤,则需要标记对象。


_ new_uuu应返回类的新的空白实例。_然后调用init_uuu初始化该实例。在"新"的"新"案例中,你不会打电话给"初始",所以它是为你打电话的。调用__new__的代码没有跟踪某个特定实例是否调用过uuinit_uuu,也不应该调用它,因为您在这里做了一些非常不寻常的事情。

您可以在uu in it_uuu函数中向对象添加一个属性,以指示它已经初始化。检查该属性是否存在,作为uu in it_uuu中的第一件事,如果存在,则不要继续。


我们应该将__init__看作是传统OO语言中的简单构造函数。例如,如果您熟悉Java或C++,则构造函数隐式地传递指向其自身实例的指针。在Java的情况下,它是EDCOX1×1变量。如果要检查为Java生成的字节码,就会发现两个调用。第一个调用是对"new"方法的调用,然后下一个调用是对init方法的调用(这是对用户定义的构造函数的实际调用)。此两步过程允许在调用类的构造函数方法(该类只是该实例的另一个方法)之前创建实际实例。

现在,对于python,__new__是一个附加的工具,用户可以访问它。Java由于其类型化的性质而不能提供灵活性。如果一种语言提供了这种功能,那么__new__的实现者在返回实例之前可以在该方法中做很多事情,包括在某些情况下创建一个完全不相关对象的新实例。而且,这种方法也适用于不可变类型,尤其是在Python中。


再深入一点!

cpython中一个泛型类的类型是type,它的基类是Object(除非您像元类一样明确定义另一个基类)。在这里可以找到低级调用的序列。第一个调用的方法是type_call,然后调用tp_new,然后调用tp_init

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

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

然后,type_call只返回绑定到变量的对象。


参考本文件:

When subclassing immutable built-in types like numbers and strings,
and occasionally in other situations, the static method new comes
in handy. new is the first step in instance construction, invoked
before init.

The new method is called with the class as its
first argument; its responsibility is to return a new instance of that
class.

Compare this to init: init is called with an instance
as its first argument, and it doesn't return anything; its
responsibility is to initialize the instance.

There are situations
where a new instance is created without calling init (for example
when the instance is loaded from a pickle). There is no way to create
a new instance without calling new (although in some cases you can
get away with calling a base class's new).

关于您希望实现的目标,在同一个文档中也有关于singleton模式的信息

1
2
3
4
5
6
7
8
9
10
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中的这个实现,使用一个修饰器

1
2
3
4
5
6
7
8
9
10
11
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...


However, I'm a bit confused as to why init is always called after new.

< /块引用>

我认为C++类比在这里是有用的:(A)new只是为对象分配内存。对象的实例变量需要内存来保存它,这就是新步骤要做的。(B)init将对象的内部变量初始化为特定值(可以是默认值)。


__new__之后调用__init__,这样当您在子类中重写它时,您添加的代码仍然会被调用。

如果您试图对已经有一个__new__的类进行子类划分,那么不知道这一点的人可能会首先修改__init__,并将调用转发给__init__子类。在__new__之后打电话给__init__的公约有助于实现预期的效果。

__init__仍然需要考虑超类__new__所需的任何参数,但如果不这样做,通常会造成明显的运行时错误。而__new__应该明确允许*args和‘**kw’,以明确扩展是可以的。

通常情况下,由于原始海报描述的行为,将__new____init__都放在同一类中,处于同一继承级别,这是不好的形式。


简单的原因是新的用于创建实例,而init用于初始化实例。在初始化之前,应该先创建实例。这就是为什么在init之前应该调用new。


However, I'm a bit confused as to why __init__ is always called after __new__.

除此之外,没有什么别的原因是这样做的。__new__不负责初始化类,其他一些方法负责初始化(__call__可能——我不确定)。

I wasn't expecting this. Can anyone tell me why this is happening and how I implement this functionality otherwise? (apart from putting the implementation into the __new__ which feels quite hacky).

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


现在我也遇到了同样的问题,出于某些原因,我决定避免使用装饰器、工厂和元类。我是这样做的:

主文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self,"parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls,"parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj

示例类

1
2
3
4
5
6
7
8
9
10
class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)

在使用中

1
2
3
4
5
6
7
8
9
10
11
>>> A(1)
A.__init__ 1  # First A(1) initialized
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>
  • 警告:您不应该初始化父级,它将与其他类冲突-除非您在每个子级中定义了单独的缓存,否则这不是我们想要的。
  • 警告:这似乎是一个家长作为祖父母的班级行为怪异。[未经证实]

尝试在线!