创建元组的子类时调用 __new__
Calling __new__ when making a subclass of tuple
在Python中,当subclassing元组时,__new__
函数以self作为参数被调用。例如,这里是 PySpark 的 Row
class:
的释义版本
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
class 定义中的 __new__
?
- 是通过
*args
吗?
__new__
是否有一些微妙的地方,它的签名可以随上下文改变?
- 或者,文档有误吗?
是否可以查看 tuple.__new__
的来源以便我自己查看答案?
我的问题不是 this one 的重复问题,因为在那个问题中,所有讨论都提到 __new__
方法,这些方法明确地将 self
或 cls
作为第一个参数。我正在努力理解
- 为什么
tuple.__new__
方法没有 self
或 cls
作为第一个参数。
- 我如何着手检查元组的源代码 class,亲眼看看到底发生了什么。
tuple.__new__
的正确签名
用 C 实现的函数和类型通常无法检查,而且它们的签名看起来总是那样。
tuple.__new__
的正确签名是:
__new__(cls[, sequence])
例如:
>>> tuple.__new__(tuple)
()
>>> tuple.__new__(tuple, [1, 2, 3])
(1, 2, 3)
毫不奇怪,这与调用 tuple()
完全一样,只是您必须重复 tuple
两次。
__new__
的第一个参数
请注意 __new__
的第一个参数始终是 class,而不是实例。其实__new__
的作用就是创建和return新的实例。
特殊方法__new__
是一个静态方法。
我这么说是因为在你的 Row.__new__
中我可以看到 self
:虽然参数的名称并不重要(使用关键字参数时除外),但请注意 self
将是 Row
或 Row
的子 class,而不是实例。一般约定是将第一个参数命名为 cls
而不是 self
.
回到你的问题
So how does self
get passed to __new__
in the Row
class definition?
当您调用 Row(...)
时,Python 会自动调用 Row.__new__(Row, ...)
。
- Is it via
*args
?
你可以这样写你的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
. Specifically, you are interested in the 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__()
。
在Python中,当subclassing元组时,__new__
函数以self作为参数被调用。例如,这里是 PySpark 的 Row
class:
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
class 定义中的 __new__
?
- 是通过
*args
吗? __new__
是否有一些微妙的地方,它的签名可以随上下文改变?- 或者,文档有误吗?
是否可以查看 tuple.__new__
的来源以便我自己查看答案?
我的问题不是 this one 的重复问题,因为在那个问题中,所有讨论都提到 __new__
方法,这些方法明确地将 self
或 cls
作为第一个参数。我正在努力理解
- 为什么
tuple.__new__
方法没有self
或cls
作为第一个参数。 - 我如何着手检查元组的源代码 class,亲眼看看到底发生了什么。
tuple.__new__
的正确签名
用 C 实现的函数和类型通常无法检查,而且它们的签名看起来总是那样。
tuple.__new__
的正确签名是:
__new__(cls[, sequence])
例如:
>>> tuple.__new__(tuple)
()
>>> tuple.__new__(tuple, [1, 2, 3])
(1, 2, 3)
毫不奇怪,这与调用 tuple()
完全一样,只是您必须重复 tuple
两次。
__new__
的第一个参数
请注意 __new__
的第一个参数始终是 class,而不是实例。其实__new__
的作用就是创建和return新的实例。
特殊方法__new__
是一个静态方法。
我这么说是因为在你的 Row.__new__
中我可以看到 self
:虽然参数的名称并不重要(使用关键字参数时除外),但请注意 self
将是 Row
或 Row
的子 class,而不是实例。一般约定是将第一个参数命名为 cls
而不是 self
.
回到你的问题
So how does
self
get passed to__new__
in theRow
class definition?
当您调用 Row(...)
时,Python 会自动调用 Row.__new__(Row, ...)
。
- Is it via
*args
?
你可以这样写你的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 haveself
orcls
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
. Specifically, you are interested in the 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__()
。