Spark Row 对象的实例化与重载原型不同?

Spark Row object instantiated differently from overloaded prototypes?

提问人:user2153235 提问时间:10/18/2023 最后编辑:user2153235 更新时间:10/25/2023 访问量:62

问:

中的 Spark 类不包含任何方法,但显示以下重载类型提示:Rowpyspark/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

上面的第二行不适合任何重载的原型。 它几乎与原型相吻合,除了所有 的参数应该是字符串。这是 显然不是 的情况,而是那个调用 在 REPL 提示符下发出时不会生成任何消息。 显然,我缺少一些关于如何 类型提示和重载有效。有人可以解释一下吗?*args*argsRow("Alice",11)

附言对于上下文, 我通过尝试查看构造函数如何达到这一点 知道在指定字段值时指定字段名称。的源代码显示,它取决于参数列表是 还是 。中的两个方法调用 本段使用 ,但 第二个根本不适合上面的原型。Row("name","age")Row("Alice", 11)__new__*args**kwargsRow*args*args

python apache-spark pyspark 重载 类型提示

评论


答:

1赞 Shubham Sharma 10/18/2023 #1

Row是 的子类,因此它的行为相应。查看源代码,我可以推断出那里使用的类型提示不执行任何运行时检查来强制执行类型(注意 [1] 下面提供了类型检查的背景)。因此,可以使用任何对象类型创建对象,而不仅仅是 int 和 strings。下面是一个例子,tupleRow

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

这里很重要的一点是还定义了方法,该方法将创建 from 字段和值的新实例。实质上,当您以这种方式调用现有对象时,现有值将成为新分配的字段Row__call__RowRow

>>> 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] 这是关于类型提示和检查的入门。第三方工具可用于检查提示指定的类型。这没有内置在像Spyder这样的IDE中

评论

0赞 user2153235 10/18/2023
这是非常有启发性的。谢谢。我希望功能行为在文档字符串中得到更多充实。我发现该方法有一些滑稽的副作用:产量。__call__Row('name', 'age')('Alice', 11)("Blah","Bleh")Row(Alice='Blah',11='Bleh')
0赞 Shubham Sharma 10/18/2023
很乐意帮忙。我同意功能行为应该更好。我看到了代码的改进空间。
1赞 user2153235 10/18/2023
还有文档字符串!我已经使用 Matlab 几十年了,您可以在其中查看源代码,但文档是编写的,因此您不必这样做。这包括数据帧和关系代数。相比之下,Spark的文档字符串似乎是针对开发人员的,他们可以毫无问题地深入研究源代码以填充功能行为的细节。这使得快速旋转更具挑战性。
1赞 user2153235 10/18/2023
另一个比较点是 Microsoft Access 的 SQL,它实际上没有源代码可以深入研究,您只需要了解 SQL(尽管 Access 很复杂,因为它不仅仅是支持 SQL)。回到 PySpark 的简陋文档字符串,公平地说,Python API 在这方面似乎是最极端的,所以它不是最具代表性的。我最近发现有一个用于 Spark 的 Matlab API,尽管没有尝试过,它似乎更适合作业提交而不是 REPL。我可能无法将文档与 Python API 的文档进行比较。