我只是试图简化我的一个类,并引入了一些与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__是创建实例的第一步。它叫做first,并且是 负责退货 类的实例。

相比之下, __init__不返回任何东西;它只负责初始化 实例。 一般来说,你不需要这样做 重写__new__,除非你 继承一个不可变类型的子类 Str, int, unicode或tuple。

从2008年4月的帖子:什么时候使用__new__ vs. __init__?在mail.python.org上。

您应该考虑到您正在尝试做的事情通常是通过Factory完成的,这是最好的方法。使用__new__不是一个好的干净的解决方案,所以请考虑使用工厂。下面是一个很好的例子:ActiveState FᴀᴄᴛᴏʀʏᴘᴀᴛᴛᴇʀɴRecipe。

其他回答

参考这个文档:

在继承不可变内置类型(如数字和字符串)时, 偶尔在其他情况下,会出现静态方法__new__ 派上了用场。__new__是实例构造的第一步,被调用 __init__之前。

__new__方法是用类来调用的 第一个参数;它的职责是返回该函数的一个新实例 类。

将其与__init__进行比较:__init__是通过实例调用的 作为它的第一个参数,它不返回任何东西;它的 职责是初始化实例。

有一些情况 在没有调用__init__(例如 当实例从pickle加载时)。没有办法去创造 一个不调用__new__的新实例(尽管在某些情况下可以 不需要调用基类的__new__)。

关于你想要达到的目标,还有关于单例模式的相同文档信息

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:
...

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

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__是实例方法。 __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:
  ...

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中的不可变类型。

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

注意:作为一个副作用,M._dict属性会自动从a中作为a ._dict访问,所以注意不要顺便覆盖它。