我只是试图简化我的一个类,并引入了一些与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__的“NEW”情况下调用__init__,所以它是为你调用的。调用__new__的代码不会跟踪__init__是否在特定实例上被调用,也不应该跟踪,因为你在这里做了一些非常不寻常的事情。

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

其他回答

在大多数知名的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

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

然而,我有点困惑,为什么__init__总是在__new__之后被调用。

没有太多的原因,除了它就是这样做的。__new__没有初始化类的责任,其他一些方法有(__call__,可能——我不确定)。

我没想到会这样。有人能告诉我为什么会发生这种情况,以及我如何实现这个功能吗?(除了将实现放在__new__中,这感觉相当粗糙)。

如果__init__已经初始化,你可以让它什么都不做,或者你可以用一个新的__call__写一个新的元类,它只在新实例上调用__init__,否则只返回__new__(…)。

当你需要控制时使用__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:
...

当__new__返回同一类的实例时,__init__随后在返回的对象上运行。也就是说,你不能使用__new__来阻止__init__被运行。即使你从__new__返回之前创建的对象,它也会被__init__一次又一次地初始化。

下面是单例模式的通用方法,它扩展了上面的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的任何真实实例。