繁体   English   中英

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

[英]Why does *args argument unpacking give a tuple?

在 python 中,可以定义一个带有任意数量的位置参数的函数,如下所示:

def f(*args):
    print(args)
f(1, 2, 3)  # (1, 2, 3)

当被调用为f(a, b, c) ,所有位置参数都放在一个tuple 中 这种行为在 python 23文档中有所描述,但我还没有找到它的 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 更倾向于易于处理而不是一致性(这似乎至少类似于兼容性破坏性更改中的兼容性)。

为什么一个函数*args (仍然)是一个tuple即使list允许更容易的进一步处理?

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

def fce1(*args):
   fce2(args)
   # some more code using args

def fce2(args):
   args.insert(0, 'other_val')

fce1(1, 2, 3)

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

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

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

args = list(args)

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

我最好的猜测是,如果 *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 成为元组而不是列表的原因可能是什么。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM