何时(以及为什么)引入了Python __new__()
函数?
创建类的实例需要三个步骤,例如MyClass()
:
MyClass.__call__()
被调用。此方法必须在MyClass
的元类中定义。MyClass.__new__()
被(__call__
)调用。在MyClass
本身上定义。这将创建实例。MyClass.__init__()
被调用(__call__
也被调用)。这将初始化实例。可以通过重载__call__
或__new__
来影响实例的创建。通常没有什么理由使__call__
而不是__new__
(例如Using the __call__ method of a metaclass instead of __new__?)超载。
我们有一些旧代码(仍然运行得很好!),其中__call__
重载了。给出的原因是__new__
当时不可用。因此,我尝试了解有关Python和我们代码的历史的更多信息,但是我不知道何时引入__new__
。
__new__
出现在documentation for Python 2.4中,而不出现在Python 2.3中,但没有出现在任何Python 2版本的whathsnew中。我可以找到的first commit that introduced __new__
(将descr-branch重新合并到主干。)是从2001年开始的,但是“ back into trunk”消息表明存在以前的情况。几个月前的PEP 252 (Making Types Look More Like Classes)和PEP 253 (Subtyping Built-in Types)似乎很重要。
进一步了解__new__
的引入将使我们更多地了解Python为何如此。
为澄清起见进行编辑:
似乎class.__new__
复制了metaclass.__call__
已经提供的功能。似乎只添加一种方法以更好地复制现有功能是不符合Pythonic的。
__new__
是您可以立即使用的少数几个类方法之一(即以cls
作为第一个参数),从而引入了以前没有的复杂性。如果类是函数的第一个参数,则可以认为该函数应该是元类的常规方法。但是该方法已经存在:__call__()
。我觉得我想念什么。
应该有一种-最好只有一种-显而易见的方法。
答案 0 :(得分:5)
博客文章The Inside Story on New-Style Classes
(摘自Guido van Rossum
(Python的BDFL)编写的 http://python-history.blogspot.com
),提供了有关此主题的一些很好的信息。
一些相关的引号:
新型类引入了新的类方法
__new__()
, 类作者自定义如何创建新的类实例。通过 覆盖__new__()
的类作者可以实现类似 单例模式,返回以前创建的实例(例如,从 空闲列表),或返回其他类的实例(例如 子类)。但是,__new__
的使用还有其他重要意义 应用程序。例如,在泡菜模块中,__new__
用于 反序列化对象时创建实例。在这种情况下,实例 创建,但未调用__init__
方法。
__new__
的另一种用途是帮助实现不可变的子类化 类型。根据其不变性的性质,这类对象可以 不能通过标准的__init__()
方法进行初始化。相反,任何 必须执行某种特殊的初始化,因为对象是 创建例如,如果该类要修改的值是 存储在不可变对象中的__new__
方法可以通过 将修改后的值传递给基类__new__
方法。
您可以阅读整篇文章,以获取有关此主题的更多信息。
与上述引用的帖子一起写的另一篇有关New-style Classes
的帖子还有一些其他信息。
修改:
为回应OP的编辑以及Python Zen的引用,我会这样说。
Zen of Python不是由该语言的创建者而是由Tim Peters编写的,仅在2004年8月19日发布。我们必须考虑到__new__
仅出现在Python 2.4文档中的事实(已在November 30, 2004上发布),并且在将__new__
引入该语言后,甚至还没有公开使用此特定准则(或格言)。
即使以前没有这样的指导性文件,我也不认为作者有意将其误解为整个语言和生态系统的设计文件。
答案 1 :(得分:3)
在这里我将不解释__new__
的历史,因为自2005年以来我才使用Python,因此在将Python引入该语言之后。但这是背后的理由。
新对象的 normal 配置方法是其类的__init__
方法。该对象已经创建(通常通过间接调用object.__new__
),该方法只是初始化。简而言之,如果您有一个真正不可变的对象,那就太迟了。
在这种使用情况下,Python方式是__new__
方法,该方法生成并返回新对象。这样做的好处是,它仍然包含在类定义中,并且不需要特定的元类。标准文档说明:
新()主要用于允许不可变类型(例如int,str或tuple)的子类自定义实例创建。在自定义元类中也通常会覆盖它,以自定义类的创建。
确实允许在元类上定义__call__
方法,但是恕我直言,它不是Python风格的,因为__new__
就足够了。此外,__init__
,__new__
和元类每个都在内部Python机制内部更深入地挖掘。因此,规则应如果__new__
足够,就不要使用__init__
,如果__new__
足够,就不要使用元类。