为什么总是在new之后调用init?

2024-04-19 07:52:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我只是想精简我的一个类,并引入了一些与flyweight design pattern风格相同的功能。

但是,我有点困惑,为什么__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

为什么?


Tags: keyself功能newreturninitdefexists
3条回答

__new__是静态类方法,而__init__是实例方法。 __new__必须先创建实例,因此__init__可以对其进行初始化。请注意,__init__self作为参数。在您创建实例之前,没有self

现在,我认为,您正在尝试用Python实现singleton pattern。有几种方法可以做到这一点。

另外,从Python 2.6开始,您可以使用类decorators

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__只不过是“allocateanewinstance”部分的每个类的类似定制。这当然允许您做一些不寻常的事情,比如返回一个现有的实例,而不是分配一个新的实例。所以在Python中,我们不应该认为这部分必然涉及到分配;我们所需要的只是__new__从某个地方找到一个合适的实例。

但它仍然只是作业的一半,而且Python系统不可能知道,有时您想在之后运行作业的另一半(__init__),有时您不想这样做。如果您想这样做,您必须明确地说。

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

元类只是类的类。类‘__call__方法控制调用类实例时发生的事情。因此,一个元类'__call__方法控制调用类时发生的事情;也就是说,它允许您从头到尾重新定义实例创建机制。这是最优雅地实现完全非标准实例创建过程(如singleton模式)的级别。事实上,只要不到10行代码,您就可以实现一个Singleton元类,它甚至根本不需要您使用__new__,只需添加__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

然而,这可能是更深的魔术比真正的理由,为这种情况!

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.

从2008年4月起,在mail.python.org上发布When to use ^{} vs. ^{}?

你应该考虑到你要做的通常是用Factory完成的,这是最好的方法。使用__new__不是一个好的清洁解决方案,因此请考虑使用工厂。这是a good factory example

相关问题 更多 >