关于python:在创建元组的子类时调用__new__

Calling __new__ when making a subclass of tuple

本问题已经有最佳答案,请猛点这里访问。

在Python中,当对元组进行子类化时,使用self作为参数调用__new__函数。例如,下面是PySark的Row类的一个解释版本:

1
2
3
class Row(tuple):
    def __new__(self, args):
        return tuple.__new__(self, args)

help(tuple)__new__没有显示self的论据:

1
2
  __new__(*args, **kwargs) from builtins.type
      Create and return a new object.  See help(type) for accurate signature.

以东十一〔五〕也说了同样的话:

1
2
__new__(*args, **kwargs)
      Create and return a new object.  See help(type) for accurate signature.

那么,在Row类定义中,self是如何传递给__new__的呢?

  • 是通过*args吗?
  • __new__是否有一些微妙之处,其签名可以随上下文而更改?
  • 或者,文档有误吗?
  • 小精灵

    是否可以查看tuple.__new__的来源,以便我自己看到答案?

    我的问题不是这个问题的复制品,因为在这个问题中,所有的讨论都提到了以selfcls为第一个论点的__new__方法。我试着理解

  • 为什么tuple.__new__方法没有selfcls作为第一个论据。
  • 我该如何检查tuple类的源代码,亲自看看到底发生了什么。

  • tuple.__new__的正确签名

    在C中实现的函数和类型通常不能被检查,它们的签名总是像那个一样。

    tuple.__new__的正确签名是:

    1
    __new__(cls[, sequence])

    例如:

    1
    2
    3
    4
    >>> tuple.__new__(tuple)
    ()
    >>> tuple.__new__(tuple, [1, 2, 3])
    (1, 2, 3)

    不足为奇,这和叫tuple()完全一样,只是你必须重复两次tuple

    __new__的第一个论点

    注意,__new__的第一个参数总是类,而不是实例。实际上,__new__的作用是创建和返回新实例。

    专用方法__new__是一种静态方法。

    我这么说是因为在你的Row.__new__中,我可以看到self:虽然参数的名称并不重要(除了使用关键字参数),但要注意,self将是RowRow的子类,而不是实例。总的惯例是将第一个论点命名为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__如下:

    1
    2
    3
    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()功能感兴趣:

    1
    2
    3
    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()的签名:

    1
    2
    3
    4
    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__()