在Python中,当子类化元组时,{self}作为参数调用__new__
函数。例如,这是PySpark的Row
类的释义版本:
class Row(tuple):
def __new__(self, args):
return tuple.__new__(self, args)
但是help(tuple)
显示self
没有__new__
参数:
__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
如何在__new__
类定义中传递给Row
?
*args
吗? __new__
是否有一些微妙之处,其签名可能会随着上下文而改变?是否可以查看tuple.__new__
的来源,以便我可以自己查看答案?
我的问题不是this one的重复,因为在该问题中,所有讨论都提到明确将__new__
或self
作为第一个参数的cls
方法。我试图理解
tuple.__new__
方法没有self
或cls
作为第一个参数。答案 0 :(得分:11)
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
。
那么
self
如何在__new__
类定义中传递给Row
?
当您致电Row(...)
时,Python会自动调用Row.__new__(Row, ...)
。
- 是通过
*args
吗?
您可以按如下方式编写Row.__new__
:
class Row(tuple):
def __new__(*args, **kwargs):
return tuple.__new__(*args, **kwargs)
这有效,而且没有任何问题。如果你不关心这些论点,那将非常有用。
__new__
是否有一些微妙之处,其签名可能会随着上下文而改变?
不,关于__new__
的唯一特殊之处在于它是一种静态方法。
- 或者,文档是否有误?
我会说它不完整或含糊不清。
- 为什么
tuple.__new__
方法没有self
或cls
作为第一个参数。
确实有,它只是没有出现在help(tuple.__new__)
上,因为C中实现的函数和方法通常不会公开这些信息。
- 我如何去研究
tuple
课程的源代码,亲眼看看自己到底发生了什么。
您要查找的文件是Objects/tupleobject.c
。具体来说,您对tuple_new()
函数感兴趣:
static char *kwlist[] = {"sequence", 0};
/* ... */
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg))
这里"|O:tuple"
表示:该函数被称为“tuple”,它接受一个可选参数(|
分隔可选参数,O
代表Python对象)。可以通过关键字参数sequence
设置可选参数。
help(type)
作为参考,您正在查看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__()
。