【问题标题】:tuples as function arguments元组作为函数参数
【发布时间】:2019-10-23 05:04:14
【问题描述】:

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

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 如何以不同的方式对待它们。

【问题讨论】:

标签: python python-3.x tuples python-internals


【解决方案1】:

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

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

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

f(*(2, 3))

【讨论】:

  • 函数调用不是赋值语句;这是一个参考映射。 谢谢! (我现在应该真的学会了!)
  • “Python 构造一个临时元组”——从概念上讲这是 Python 所做的,但实际上它只是将对象推入堆栈并再次弹出它们。从未创建元组。尝试查看执行 a, b = b, a 的函数的 dis.dis 输出。
【解决方案2】:

元组的行为就像一个不可变的列表。您用括号表示它们的事实可能令人困惑,但这或多或少是一个巧合 - 括号用于对事物进行分组这一事实的结果一起减少歧义。

当你调用一个函数时,你并没有提供一个元组。你在提供论据。一个元组可以是一个参数,但只有一个 - 它只是一个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

总之,

  • 函数的构建方式可以接受任意数量的参数
  • *** 运算符能够在一端解压缩元组/列表/字典到参数中,而在另一端打包它们李>
  • 单独的元组/列表/字典否则只是单独的变量。

【讨论】:

  • 我觉得这并不能真正回答他的问题,他在问为什么 func(2, 3) 中的 2, 3 不是元组。如果括号是可选的,应该是这样。
  • 因为这就是语言的定义方式。元组是一种数据类型,就像任何其他类型的变量一样。函数接受一系列参数(各种类型的) - 而不仅仅是一个恰好包含其余参数的参数。虽然确实有许多函数(例如threading 的东西)使用元组来指定要为函数提供哪些参数,但这是没有必要的(提供一组 args 作为变量)。
【解决方案3】:

问题是,括号在 Python 中用于多种不同的事情——用于调用函数,用于制作元组(重要的不仅仅是逗号,请参阅空元组 ()),用于更改表达式中的评估优先级。

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

如果 Python 解析器被实现为将其解析为一个元组,那么函数就不可能有多个参数。如果 Python 解析器被实现为将其解析为两个参数,则不可能在没有括号的情况下传递文字元组。

显然第一个限制更大,所以选择了第二个。

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

【讨论】:

    猜你喜欢
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-05
    • 1970-01-01
    相关资源
    最近更新 更多