我相信我对
__new__
应该做什么有某种理解(创建一个类的实例,但不初始化它,这是__init__
的工作)。但是,我想了解 Python 3 默认情况下将什么实现为 __new__
方法。
我还发现
cls
是 __new__
的参数有点令人困惑,但是 __new__
是静态方法而不是类方法(我从 documentation 中得到这个)。它怎么知道它被传递一个类型作为它的第一个参数?
第一部分:
__new__
默认做什么?因为从头开始创建对象是一项基本的、特定于实现的操作,所以object.__new__
的定义(就像object
的其余定义一样)必然是实现本身的一部分。这意味着您需要查看 CPython、PyPy、Cython 等的源代码,以准确了解在任何特定的 Python 实现中如何管理对象创建。通常,它都是无法直接从 Python 本身访问的低级簿记。
第二部分:
__new__
怎么知道它得到一个类参数?因为它 assumes 它的第一个参数是一个类,如果调用者希望 __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(...)
。 这是管理的,因为__call__
元类的Foo
方法负责为您调用__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__
。
根据我的理解,
__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
希望这能回答你的问题
你的问题是
如果我们不覆盖它,那么
在 Python 中做什么?__new__
假设我们有一个非常简单的类,名为
Point
。我们实例化Point
类如下:
# construct and initialize paula the point
paula = Point(10.2, 7.4)
为了帮助解释
__new__
的作用,我将编写一个名为make_point
的类方法,它与调用类构造函数的行为几乎相同,例如paula = = Point(10.2, 7.4)
。
class Point():
def __new__(cls, *args, **kwargs):
print("__new__(" + ", ".join(str(x) for x in [cls, *args]) + ")")
obj = super().__new__(cls)
return obj
def __init__(self, y:float, y:float):
args = (y, y)
print("__init__(" + ", ".join(str(x) for x in [self, *args]) + ")")
self._y = y
self._y = y
@classmethod
def make_point(cls, *args):
new_instance = cls.__new__(cls, *args)
if isinstance(new_instance, cls):
cls.__init__(new_instance, *args)
return new_instance
现在我们可以实例化
Point
类如下:
peter = Point.make_point(59.87, 5.91)