阅读文档,我发现了一种通过传递参数调用方法的实现。
def printArgs(a, b):
print(f"a = {a}, b = {b}")
printArgs(*(2,3))
printArgs(2,3)
我不太明白*如果你可以只列出参数而无需指针,为什么要用它来传递参数?
另外,据我了解,传递starred_and_keywords首先发生,因此使用指针传递参数b会引发错误:
printArgs(a=1, *(2,))
Traceback (most recent call last):
File "C\...", line 4, in <module>
printArgs(a=1, *(2,))
TypeError: printArgs() got multiple values for argument 'a'
如果您手动在代码中显式编写参数,那么使用星号解包确实没有意义。
但是,如果您的参数集是在代码中的另一个位置形成的,并且您事先不知道会有多少个参数,那么您就不能没有星号。
例子:
*“解包”iterable,所以是的,事实证明:如果您解包的不是一个常量元组(那么用星号表示确实没有意义),而是一个生成器、列表或带有变量的元组等,这会很方便。
事实上,如果某个函数是这样描述的
def func(*args, **kwargs),那么如果你在通过调用它时向它传递参数,就会发生“双重魔法”func(*args, **kwargs)。比方说:
然后:
在这种情况下,反向打包发生在函数本身内部:
为什么需要这一切?为了多功能性。您可以通过简单地列出位置变量和命名变量,或者通过从
iterable(args) 和/或字典 ( )中“解压”它们(或其中一些)来显式传递它们kwargs。同样的事情也发生在函数本身中。您可以通过列出函数参数来显式描述它们,也可以将输入参数“打包”到
*args和 中**kwargs。这为传递和处理参数提供了很大的灵活性。第一个问题“为什么用它
*来传递参数”的答案在前面已经部分给出,即:参数列表可以取决于任务执行的上下文。我将用以下例子来补充:您可以将列表作为单个实体来使用。例如,这是
point三维空间中的一个点。该函数f需要三个单独的坐标作为参数。然后你有两种选择:要么引入新变量x, y, z = point; f(x, y, z),要么在调用函数时解压点f(*point)。您希望该函数不与对象一起工作,而是与它们的组成部分一起工作。例如,您有 2 个单词
a = 'one'; b = 'two',并且想要使用 写出所有以逗号分隔的字母f = lambda *args: ','.join(args)。该调用f(a, b)将返回用逗号分隔的相同单词。为了得到你想要的,你需要解压这些词:f(*a, *b)。另一个类似的例子是将列表列表转置为zip:您可能需要传递设置,将其存储为字典而不是单个变量更方便。例如,在读取 CSV 文件时,您可以构建设置字典
settings = {'delimiter': '|', 'lineterminator': ','}并在调用 时将其解压csv.reader(file, **settings)。关于第二个问题“TypeError: printArgs() got multiple values for argument 'a'” ,在以下文档段落中进行了描述:
换句话说,当调用时,
printArgs(a=1, *(2,))位置参数将首先从 tuple 中填充(2,),之后命名变量a=1将相对于声明的参数的顺序进行定位。由于它落入第一个位置,该位置已经被两个占据,因此TypeError在引用的最后一句中提到。**kwargs不能放在前面*args,会出错。如果同时发送
*args和,则先于 进行处理。**kwargs*args**kwargs