python - 创建元组的子类时调用 __new__

标签 python class subclass pyspark subclassing

<分区>

在 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__ 方法,这些方法明确地将 selfcls 作为第一个参数。我在努力理解

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

最佳答案

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


回到你的问题

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 .具体来说,您对 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__()

关于python - 创建元组的子类时调用 __new__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34464068/

相关文章:

python - 从 python 列表中删除不必要的项目

python - 如何在使用 pandas datetime 时指定日期?

python - 在 Fabric 中,如何从另一个 python 文件执行任务?

python - ffmpeg Python 子进程错误返回非零退出状态 1

c# - 如何在另一个类中的类中添加数据

ios - UIView 子类不能使用 UIView 自定义类?

php - PHP 类属性可以等于另一个类属性吗?

java - 反射:将对象转换为子类而不使用 instanceof

c++ - 在类中子类化按钮控件

ios - 在 Swift 中子类化 NSObject - 初始化器的最佳实践