为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 *args 参数解包会给出一个元组?

为什么 *args 参数解包会给出一个元组?

缥缈止盈 2021-10-10 16:09:27
在 python 中,可以定义一个带有任意数量的位置参数的函数,如下所示:def f(*args):    print(args)f(1, 2, 3)  # (1, 2, 3)当调用 as 时f(a, b, c),所有位置参数都放在一个元组中。这种行为在 python 2和3文档中有所描述,但我还没有找到它的 PEP。PEP 3132,first, *middle, last = seqence在“接受”下引入扩展的可迭代解包 ( ) 状态,即使加星标的目标成为元组而不是列表。这将与函数的 *args 一致,但会使结果的进一步处理更加困难。进行了讨论。如果我写了一个包装器,我可能还想进一步处理这样的参数:def force_type(position, type):    def wrapper(f):        def new(*args, **kwargs):            args = list(args)  # Why?            args[position] = type(args[position])            return f(*args, **kwargs)        return new    return wrapper@force_type(1, int)def func(a, b, c):    assert isinstance(b, int)这进一步处理由较硬的事实args是一个tuple。在引入的早期阶段是否没有使用包装器?如果是这样,为什么这在 python3 中没有通过其他兼容性破坏性更改进行更改(PEP3132 更倾向于易于处理而不是一致性(这似乎至少类似于兼容性破坏性更改中的兼容性)。为什么 a 函数*args(仍然)atuple即使 alist允许更容易的进一步处理?
查看完整描述

3 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

我不知道这是否是它背后的想法,但是处理的简便性(即list使用tuple数据实例化 a并不难)可能会出现令人困惑的行为。


def fce1(*args):

   fce2(args)

   # some more code using args


def fce2(args):

   args.insert(0, 'other_val')


fce1(1, 2, 3)

编写fce1代码的人可能会感到惊讶,因为args他们没有意识到他们稍后处理的不是调用函数的内容。


我还认为不可变类型在内部更容易处理并且开销更少。


查看完整回答
反对 回复 2021-10-10
?
MMTTMM

TA贡献1869条经验 获得超4个赞

我最好的猜测是,如果 *args 生成一个列表(可变),它会在多种情况下导致非常令人惊讶的结果。@Ondrej K. 给出了一个很好的例子。打个比方,当有一个列表作为默认参数时,每个函数调用可能有不同的默认参数。这是默认参数只计算一次的结果,这种情况不是最直观的。即使是官方的 python 文档也有针对这种情况的特定解决方法。


执行函数定义时从左到右计算默认参数值。这意味着表达式会在定义函数时计算一次,并且每次调用都使用相同的“预计算”值。这对于理解何时默认参数是可变对象(例如列表或字典)尤其重要:如果函数修改了对象(例如,通过将项目附加到列表),则默认值实际上被修改了。这通常不是预期的。解决这个问题的一种方法是使用 None 作为默认值,并在函数体中明确测试它,例如:


def whats_on_the_telly(penguin=None):

if penguin is None:

    penguin = []

penguin.append("property of the zoo")

return penguin


总而言之,我认为 *args 是一个元组,因为将它作为列表会导致与可变类型相关的所有问题(如速度较慢),更大的问题是大多数人不希望函数参数发生变化。尽管我确实同意这种实现与PEP-3132非常不一致,并且会导致大多数学习者感到困惑。我对 Python 非常陌生,为了与PEP-3132 的接受保持一致,我花了一段时间才理解 *args 成为元组而不是列表的原因可能是什么。


查看完整回答
反对 回复 2021-10-10
?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

为什么不?关于元组的事情是,你不能在创建后改变它。这允许提高执行脚本的速度,并且您实际上不需要函数参数列表,因为您实际上不需要修改函数的给定参数。你需要为你的参数附加或删除方法吗?在大多数情况下,它不会。你想让你的程序运行得更快吗?那会是的。这就是大多数人喜欢拥有东西的方式。*args 的东西因此返回元组,如果你真的需要一个列表,你可以用一行代码来转换它!

args = list(args)

所以总的来说:它可以加快您的程序执行速度。你不要改变论据。改变它的类型并不难。


查看完整回答
反对 回复 2021-10-10
  • 3 回答
  • 0 关注
  • 254 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信