什么时候(以及为什么)引入了Python`__new __()`?

时间:2019-05-03 09:17:33

标签: python oop python-2.x

何时(以及为什么)引入了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__()。我觉得我想念什么。

  

应该有一种-最好只有一种-显而易见的方法。

2 个答案:

答案 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__足够,就不要使用元类。