我只是试图简化我的一个类,并引入了一些与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?


当前回答

__new__是静态类方法,而__init__是实例方法。 __new__必须先创建实例,所以__init__可以初始化它。注意,__init__以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:
  ...

其他回答

当实例化一个类时,首先调用__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

我知道这个问题很老了,但我也遇到过类似的问题。 以下是我想要的:

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

One should look at __init__ as a simple constructor in traditional OO languages. For example, if you are familiar with Java or C++, the constructor is passed a pointer to its own instance implicitly. In the case of Java, it is the this variable. If one were to inspect the byte code generated for Java, one would notice two calls. The first call is to an "new" method, and then next call is to the init method (which is the actual call to the user defined constructor). This two step process enables creation of the actual instance before calling the constructor method of the class which is just another method of that instance.

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

@AntonyHatchkins回答的更新,您可能需要为元类型的每个类创建一个单独的实例字典,这意味着您应该在元类中使用__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符号(在类参数中无参数调用super和元类,而不是作为属性)。

无论哪种方式,这里的重点是,如果找到键,您的类初始化器(__call__方法)将不会执行__new__或__init__。这比使用__new__干净得多,如果你想跳过默认的__init__步骤,则需要标记对象。

引用文件:

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.