如何理解 Python 函数签名中的 * 和 object_list = ...?
数据小陈
这个理解不正确。签名中的裸 * 表示后面的普通参数只能通过关键字传入;object_list = ... 表示该参数有默认值。如果这是实际执行的 Python 函数定义,默认值就是 Ellipsis 对象。它们都不表示“接收任意数量的必需位置参数”或“实现稍后补充”。
逐项理解函数签名
def get_context_data(self, *, object_list = ..., **kwargs):
self:实例方法的第一个参数,通过实例调用方法时,Python 会自动绑定它。*:位置参数与仅限关键字参数之间的分隔符,本身不接收参数。传入object_list时,必须写成object_list=值。object_list = ...:object_list可以省略;省略时,默认值为Ellipsis。**kwargs:将其他未匹配到具名参数的关键字参数收集到字典中,可以为空。
接收任意数量位置参数的写法是 *args。原签名只有裸 *,所以通过实例调用时,不能额外传入位置参数。
用一个可运行的示例观察结果
原代码没有展示有效的类和方法体缩进。下面补齐缩进,并用返回值演示参数绑定:
class MyObject:
def get_context_data(self, *, object_list = ..., **kwargs):
return object_list, kwargs
obj = MyObject()
print(obj.get_context_data())
# (Ellipsis, {})
print(obj.get_context_data(object_list=[1, 2], page=3))
# ([1, 2], {'page': 3})
print(obj.get_context_data(object_list=None))
# (None, {})
# 以下调用会抛出 TypeError:object_list 不能按位置传入
# obj.get_context_data([1, 2])
object_list 是签名中明确声明的参数,不会被收入 kwargs。示例中的 page 会进入这个字典。
... 是否表示占位?
... 是 Python 的合法字面量,求值结果是内置单例对象 Ellipsis。在实际执行的函数定义中,可以用它区分调用者没有提供参数和调用者传入 None 的情况:
if object_list is Ellipsis:
# 处理默认值的情况
pass
不过,调用者显式传入 object_list=... 时也会满足这个判断。仅凭签名,无法断定作者是否打算把它用作“未提供参数”的标记。
如果这个签名来自 .pyi 类型存根,= ... 通常表示该参数有默认值,但没有写出具体的默认值。此时不能据此断定实际运行时的默认值也是 Ellipsis。原问题没有提供代码来源,因此需要区分这两种情况。
super() 调用不会自动转发参数
原代码中的这一行:
context = super().get_context_data()
没有向父类方法显式传入 object_list 或 kwargs,Python 也不会自动转发它们。如果父类方法接受这些参数,且当前方法需要继续传递,可以写成:
context = super().get_context_data(
object_list=object_list,
**kwargs,
)
是否应该这样修改,取决于父类方法的签名和默认值约定。原片段没有提供这些信息,无法直接确定。
备注:内容仅供参考。
