元组作为函数参数

tuples as function arguments

a tuple in python(在代码块中)由逗号定义;括号不是强制性的(在以下情况下)。所以这三个都是等价的:

a, b = 1, 2
a, b = (1, 2)
(a, b) = 1, 2

如果我定义一个函数

def f(a, b):
    print(a, b)

这样调用就可以了:

f(2, 3)

这不会:

f((2, 3))
# TypeError: f() missing 1 required positional argument: 'b'

当元组是函数参数时,python 如何区别对待元组?这里的括号是必要的(我理解 为什么 是这种情况,我很高兴 python 以这种方式工作!)。

我的问题是:当元组是函数参数时,python 如何区别对待它们。

元组的行为类似于不可变列表。您用圆括号标记它们的事实可能令人困惑,但这或多或少是巧合 - 这是圆括号事实的结果用于将事物组合在一起并减少歧义。

调用函数时,您并没有提供元组。你在提供论据。元组 可以是 一个参数,但只有一个 - 它只是一个 tuple.

类型的变量

你可以做的是将元组(或列表)扩展为一系列具有以下表示法的参数:

tup = (2, 3)
f(*tup)
# expand the tuple (2,3) into a series of arguments 2, 3

你也可以用字典来做到这一点,除了 ** 而不是 *:

my_dict = {"arg1": 1, "arg2": 2}
f(arg1=my_dict["arg1"], arg2=my_dict["arg2"])
f(**my_dict)   # these are equivalent

另一方面,函数可以接受任意数量的参数(类似于其他语言对 printf() 调用的处理方式)。例如:

def g(*args):
    print("I got this many arguments:", len(args))

在这里,如果你做type(args),你会得到tuple,如果你做type(*args),你会得到一个错误。这是因为,在函数头中,* 的作用恰恰相反:它将提供给函数的参数打包到单个元组中,以便您可以使用它们。考虑以下因素:

g(2, 3)  # 2 arguments, both integers
g((2, 3)) # 1 argument, a tuple
g(*(2, 3)) # 2 arguments, both integers

简而言之,

  • 函数的构建方式可以接受任意数量的参数
  • *** 运算符能够在一端 解压 tuples/lists/dicts 为参数,并且 打包他们在另一端
  • 个体 tuples/lists/dicts 否则只是个体变量。

为方便起见,Python根据赋值语句的需要构造一个临时元组。因此,一旦到达数据移动,您的所有三个赋值语句都完全相同。

函数调用不是赋值语句;这是一个参考映射。因此,语义不同。

如果您希望 Python 将您的元组解压缩为两个单独的参数,请使用 * 运算符:

f(*(2, 3))

问题是括号在 Python 中用于多种不同的用途——用于调用函数,用于生成元组(重要的不是 只是 逗号,请参阅空元组 ()),以更改表达式中的求值优先级。

在解释它们不明确的情况下(例如,您的示例 f(2, 3) 可以是带有两个参数的函数调用,也可以是带有一个元组参数的函数调用),语言必须做出选择.

如果实现了 Python 解析器,以便将其解析为一个元组,则不可能有具有多个参数的函数。如果实现了 Python 解析器以便将其解析为两个参数,则不可能传递没有括号的文字元组。

显然第一个的限制要大得多,因此选择了第二个。

另一个例子是带有 一个 元素的元组——(1+2) 是一个产生数字 3 的表达式,还是一个只有一个元素 3 的元组?这里如果是第二个,那么就不可能在表达式中使用括号来表示优先级((3+4)*5 vs 3+(4*5))。因此决定要求单元素元组的第一个元素后有逗号 ((3,)).