【问题标题】:What's ```__new__``` by default in Python 3?Python 3 中默认的 ```__new__``` 是什么?
【发布时间】:2019-12-16 16:18:50
【问题描述】:

我相信我对__new__ 应该做什么有一定的了解(创建一个类的实例,但不初始化它,这是__init__ 的工作)。但是,我想了解 Python 3 默认将什么实现为 __new__ 方法。

我还觉得 cls__new__ 的参数有点令人困惑,但 __new__ 是静态方法而不是类方法(我从 documentation 得到这个)...它被传递一个类型作为它的第一个参数?

【问题讨论】:

  • 1. object.__new__是默认的,有什么要了解的? 2. 通过检查isinstance(cls, type) 或实现语言中的等效项。
  • @juanpa.arrivillaga 我从来没有参与过 CPython 的实现,你能解释一下那里发生了什么吗?看起来类似于 self.__init__() 的东西被返回了?
  • @Goyo 你什么意思?如果object.__new__ 是默认值,它的作用是什么?我在哪里可以找到这些信息?另外,将 cls 作为参数呢? __new__ 是类方法吗?
  • @juanpa.arrivillaga 这可以用纯python重新创建还是不可能?

标签: python python-3.x default-constructor class-constructors


【解决方案1】:

根据我的理解,__new__() 的默认实现是这样的

class Default(object):
def __new__(cls, *args, **kwargs):
    print("In new")
    return super().__new__(cls,*args, **kwargs)

def __init__(self):
    print("In init default")

default = Default()
print(type(default))

输出

In new
In init default
<class '__main__.Default'>

根据文档 https://docs.python.org/3/reference/datamodel.html#object.new

典型实现通过使用 super().new(cls[, ...]) 调用超类的 __new__() 方法和适当的参数来创建类的新实例,然后修改新的- 在返回之前根据需要创建实例。

super().__new__() 调用将创建实例,__init__() 将初始化。

下面的代码显示了 __new__() 的错误覆盖

class InccorectOverride(object):

def __new__(cls, *args, **kwargs):
    pass

def __init__(self):
    print("In init InccorectOverride")

a = InccorectOverride()
print(type(a))

输出

<class 'NoneType'>

由于__new__()没有返回实例,所以输出的值为NoneType

希望这能回答你的问题

【讨论】:

    【解决方案2】:

    第一部分:__new__ 默认是做什么的?因为从头开始创建对象是一个基本的、特定于实现的操作,所以object.__new__ 的定义必然(就像object 的其余定义一样)是实现本身的一部分。这意味着您需要查看 CPython、PyPy、Cython 等的源代码,以准确了解在 Python 的任何特定实现中如何管理对象创建。通常情况下,这些都是无法从 Python 本身直接访问的低级簿记。

    第二部分:__new__ 怎么知道它得到了一个类参数?因为它假设它的第一个参数是一个类,如果调用者希望__new__ 正常工作,最好提供一个类!也就是说,没有人真正明确地调用过__new__,除非通过super 覆盖__new__,然后,您必须确保自己明确传递cls

    def __new__(cls, *args, **kwargs):
        rv = super().__new__(cls, *args, **kwargs)  # Not super().__new__(*args, **kwargs)
    

    其余时间,您创建类Foo 的实例不是通过直接调用Foo.__new__(Foo, ...),而是通过调用类型本身:Foo(...)这个是管理的,因为Foo 的元类的__call__ 方法负责为您调用__new__。比如你可以想象type.__call__大致定义为

    # A regular instance method of type; we use cls instead of self to
    # emphasize that an instance of a metaclass is a class
    def __call__(cls, *args, **kwargs):
        rv = cls.__new__(cls, *args, **kwargs)  # Because __new__ is static!
        if isinstance(rv, cls):
            rv.__init__(*args, **kwargs)
        return rv
    

    请注意,__init__ 仅在 __new__ 实际返回调用 __new__ 的类的实例时才被调用。

    【讨论】:

    • 啊哈,我现在知道这就是我要找的东西。你对__call__ 工作原理的粗略想法让我很满意。我认为在这种情况下,我可以更好地理解__new__ 的作用。
    猜你喜欢
    • 1970-01-01
    • 2012-07-04
    • 2014-03-01
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多