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

然而,我有点困惑,为什么__init__总是在__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

Why?


当前回答

引用文件:

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.

其他回答

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

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

Python的__new__就是类似的“分配新实例”部分的每个类自定义。当然,这允许您做一些不寻常的事情,比如返回一个现有的实例,而不是分配一个新实例。所以在Python中,我们不应该认为这部分涉及到分配;我们所需要的只是__new__从某个地方提供一个合适的实例。

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

通常,你可以重构,这样你只需要__new__,或者你不需要__new__,或者让__init__在一个已经初始化的对象上表现不同。但如果你真的想这样做,Python实际上允许你重新定义“作业”,这样SomeClass(arg1, arg2)就不一定会调用__new__后跟__init__。要做到这一点,你需要创建一个元类,并定义它的__call__方法。

A metaclass is just the class of a class. And a class' __call__ method controls what happens when you call instances of the class. So a metaclass' __call__ method controls what happens when you call a class; i.e. it allows you to redefine the instance-creation mechanism from start to finish. This is the level at which you can most elegantly implement a completely non-standard instance creation process such as the singleton pattern. In fact, with less than 10 lines of code you can implement a Singleton metaclass that then doesn't even require you to futz with __new__ at all, and can turn any otherwise-normal class into a singleton by simply adding __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

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

引用文件:

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.

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

你可以在__init__函数中为对象添加一个属性,以表明它已被初始化。检查该属性是否作为__init__中的第一个属性存在,如果已经存在,则不要继续进行任何操作。

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

如果你试图子类化一个已经有__new__的类,不知道这一点的人可能会通过调整__init__开始,并将调用转发到子类__init__。这种在__new__之后调用__init__的约定有助于按预期工作。

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

在同一个类中同时拥有__new__和__init__在同一继承级别通常是不好的形式,因为原来的海报所描述的行为。

当实例化一个类时,首先调用__new__()来创建类的实例,然后调用__init__()来初始化实例。

__new__ ():

调用它来创建类cls. ...的新实例 如果在对象构造期间调用__new__(),它返回一个 实例,则新实例的__init__()方法将为 像__init__(self[,…])一样调用,…

__init__ ():

在实例创建后调用(通过__new__()),… 因为__new__()和__init__()在构造对象时一起工作 (__new__()来创建它,__init__()来定制它),…

例如,在实例化Teacher类时,首先调用__new__()来创建Teacher类的实例,然后调用__init__()来初始化实例,如下所示:

class Teacher:
    def __init__(self, name):
        self.name = name
        
class Student:
    def __init__(self, name):
        self.name = name

obj = Teacher("John") # Instantiation

print(obj.name)

输出如下:

<class '__main__.Teacher'>
John

并且,使用Teacher类实例的__new__(),我们可以创建Student类的实例,如下所示:

# ...

obj = Teacher("John")
print(type(obj))
print(obj.name)

obj = obj.__new__(Student) # Creates the instance of "Student" class
print(type(obj))

现在,创建了Student类的实例,如下所示:

<class '__main__.Teacher'>
<__main__.Teacher object at 0x7f4e3950bf10>
<class '__main__.Student'> # Here

接下来,如果我们尝试从Student类的**实例中获取name变量的值,如下所示:

obj = Teacher("John")
print(type(obj))
print(obj.name)

obj = obj.__new__(Student)
print(type(obj))
print(obj.name) # Tries to get the value of "name" variable

发生以下错误是因为Student类的实例还没有被__init__()初始化:

AttributeError: 'Student'对象没有属性'name'

因此,我们初始化Student类的实例,如下所示:

obj = Teacher("John") 
print(type(obj))
print(obj.name)

obj = obj.__new__(Student)
print(type(obj))
obj.__init__("Tom") # Initializes the instance of "Student" class
print(obj.name)

然后,我们可以从Student类的实例中获取name变量的值,如下所示:

<class '__main__.Teacher'>
John
<class '__main__.Student'>
Tom # Here