Row
中的 Spark pyspark/sql/types.py
类不包含 __init__
方法,但显示以下 __new__
的重载类型提示:
@overload
def __new__(cls, *args: str) -> "Row"
@overload
def __new__(cls, **kwargs: Any) -> "Row"
def __new__(cls, *args: Optional[str], **kwargs: Optional[Any]) -> "Row"
Row
的文档字符串显示了各种实例化:
>>> Person = Row("name", "age")
>>> row1 = Row("Alice", 11) # This is the one that is hard to understand
>>> row2 = Row(name="Alice", age=11)
>>> row1 == row2
True
上面的第二行不适合任何重载原型。 它几乎适合原型与
*args
,除了以下事实:
*args
的参数应该是 strings。这是
显然不是 Row("Alice",11)
的情况,但是调用
在 REPL 提示符下发出时不会生成任何消息。
显然,我缺少一些关于如何
类型提示和重载有效。有人可以解释一下吗?
P.S. 对于上下文, 我通过尝试了解构造函数如何达到这一点 知道
Row("name","age")
指定字段名称,而
Row("Alice", 11)
指定字段值。源代码为
__new__
表明这取决于参数列表是否
*args
或**kwargs
。两个 Row
方法调用
本段使用 *args
,但是
第二个根本不符合上面*args
的原型。
Row
是 tuple
的子类,因此它的行为也相应。查看源代码,我可以推断出那里使用的类型提示不会执行任何运行时检查来强制类型(下面的注释 [1] 提供了类型检查的背景)。因此,可以使用任何对象类型创建 Row
对象,而不仅仅是 int 和字符串。这是一个例子,
class Foo:
pass
class Bar:
pass
>>> Row(Foo(), Bar())
# <Row(<__main__.Foo object at 0x7f5bb3ef4700>, <__main__.Bar object at 0x7f5bb36458d0>)>
仅使用
args
创建行对象不会自动设置 __fields__
参数。因此,您的假设“对于上下文,我通过尝试查看构造函数如何知道 Row("name","age")
指定字段名称而 Row("Alice", 11)
指定字段值”来达到这一点是不正确的。
默认情况下,两者都会设置元组的值。这就是为什么在你的例子中
row1 == row2
>>> row = Row('name', 'age')
>>> row.__fields__
# AttributeError: __fields__
>>> row1 = Row("Alice", 11)
>>> row2 = Row(name="Alice", age=11)
>>> row1 == row2
# True
这里重要的一点是
Row
还定义了 __call__
方法,它将根据字段和值创建 Row
的新实例。本质上,当您以这种方式调用现有 Row
对象时,现有值将成为新分配的字段
>>> row = Row('name', 'age')('Alice', 11)
>>> row
# Row(name='Alice', age=11)
>>> row.__fields__
>>> <Row('name', 'age')>
但是当您使用
kwargs
表单时,字段和值会自动设置,
>>> row = Row(name="Alice", age=11)
>>> row
# Row(name='Alice', age=11)
>>> row.__fields__
# ['name', 'age']
备注:
[1] Here 是类型提示和检查的入门知识。可以使用第三方工具来检查提示指定的类型。这未内置于 Spyder 等 IDE 中。