在 Python 中,当对元组进行子类化时,__new__
函数以 self 作为参数被调用。例如,这里是 PySpark 的 Row
类的释义版本:
class Row(tuple):
def __new__(self, args):
return tuple.__new__(self, args)
但是 help(tuple)
没有向 __new__
显示 self
参数:
__new__(*args, **kwargs) from builtins.type
Create and return a new object. See help(type) for accurate signature.
和help(type)
只是说同样的事情:
__new__(*args, **kwargs)
Create and return a new object. See help(type) for accurate signature.
那么 self
是如何传递给 Row
类定义中的 __new__
的呢?
- 是通过
*args
吗?
__new__
是否有一些微妙的地方,它的签名可以随上下文改变?
- 或者,文档是否有误?
是否可以查看 tuple.__new__
的源代码以便我自己找到答案?
我的问题不是 this one 的重复问题因为在那个问题中,所有讨论都涉及 __new__
方法,这些方法明确地将 self
或 cls
作为第一个参数。我在努力理解
- 为什么
tuple.__new__
方法没有 self
或 cls
作为第一个参数。
- 我将如何着手检查元组类的源代码,亲自了解到底发生了什么。
tuple.__new__
的正确签名
用 C 实现的函数和类型通常无法检查,并且它们的签名总是看起来像那个。
tuple.__new__
的正确签名是:
__new__(cls[, sequence])
例如:
>>> tuple.__new__(tuple)
()
>>> tuple.__new__(tuple, [1, 2, 3])
(1, 2, 3)
毫不奇怪,这与调用 tuple()
完全一样,只是您必须重复 tuple
两次。
__new__
的第一个参数
请注意,__new__
的第一个参数始终是类,而不是实例。实际上,__new__
的作用就是创建并返回新的实例。
特殊方法__new__
是一个静态方法。
我这么说是因为在你的 Row.__new__
中我可以看到 self
: 虽然参数的名称并不重要(使用关键字参数时除外),请注意 self
将是 Row
或 Row
的子类,而不是实例。一般约定是将第一个参数命名为 cls
而不是 self
。
回到你的问题
So how does self
get passed to __new__
in the Row
class definition?
当您调用 Row(...)
时,Python 会自动调用 Row.__new__(Row, ...)
。
您可以按如下方式编写您的Row.__new__
:
class Row(tuple):
def __new__(*args, **kwargs):
return tuple.__new__(*args, **kwargs)
这是可行的,而且没有任何问题。如果您不关心参数,这将非常有用。
- Does
__new__
have some subtlety where its signature can change with context?
不,__new__
唯一特别的地方在于它是一个静态方法。
- Or, is the documentation mistaken?
我会说它不完整或模棱两可。
- Why the
tuple.__new__
method does not have self
or cls
as first argument.
它确实有,只是没有出现在 help(tuple.__new__)
中,因为 C 中实现的函数和方法通常不会公开这些信息。
- How I might go about examining the source code of the
tuple
class, to see for myself what's really going on.
您要查找的文件是Objects/tupleobject.c
.具体来说,您对 tuple_new()
感兴趣功能:
static char *kwlist[] = {"sequence", 0};
/* ... */
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
这里 "|O:tuple"
的意思是:这个函数被称为“元组”,它接受一个可选参数(|
分隔可选参数,O
代表一个 Python 对象)。可选参数可以通过关键字参数 sequence
设置。
关于帮助(类型)
作为引用,您正在查看 type.__new__
的文档,而您应该停在 help(type)
的前四行:
在 __new__()
的情况下,正确的签名是 type()
的签名:
class type(object)
| type(object_or_name, bases, dict)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
但这无关紧要,因为 tuple.__new__
具有不同的签名。
记住super()
!
最后但同样重要的是,尝试使用 super()
而不是直接调用 tuple.__new__()
。