在创建元组的子类时调用__new__

时间:2015-12-25 15:27:41

标签: python class subclass pyspark subclassing

在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方法。我试图理解

  1. 为什么tuple.__new__方法没有selfcls作为第一个参数。
  2. 我如何去检查元组类的源代码,亲眼看看它到底发生了什么。

1 个答案:

答案 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将会是RowRow的子类,而不是实例。一般约定是将第一个参数命名为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__方法没有selfcls作为第一个参数。
  •   

确实有,它只是没有出现在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__()