【问题标题】:Is it safe to rely on Python function arguments evaluation order? [duplicate]依赖 Python 函数参数评估顺序是否安全? [复制]
【发布时间】:2013-07-30 16:18:10
【问题描述】:

假设函数参数在 Python 中从左到右计算是否安全?

参考说明它是这样发生的,但也许有一些方法可以改变这个顺序,这可能会破坏我的代码。

我要做的是为函数调用添加时间戳:

l = []
l.append(f(), time.time())

我知道我可以按顺序评估参数:

l = []
res = f()
t = time.time()
l.append(res, t)

但它看起来不太优雅,所以如果我可以依赖它,我更喜欢第一种方式。

【问题讨论】:

  • 如果参考文献是这样说的,并且没有明确说明将来可能会改变,那么您可以依赖它。
  • "some way to change this order" 怎么改? (函数无法选择如何评估它们的参数,它们在被传递给函数之前被评估)
  • 在您的用例中,评估顺序似乎并不重要,除非 f() 是一个长期运行的函数。
  • @DavidRobinson 据我记得在 C 中你不能依赖它。通常根据 __stdcall (或其他)从右到左评估参数,以便堆栈中的顺序方便。我想也许在 python 中有一个类似的技巧来改变这个顺序
  • 我不同意顺序版本不太优雅;它使依赖关系明确。有多少读过你的代码的人会知道 Python 肯定会强制执行顺序?

标签: python arguments operator-precedence


【解决方案1】:

引用reference documentation:

Python 从左到右计算表达式。

所以是的,您可以信赖这一点(有一个例外,见下文)。

一个调用(主要之后的(...)部分,例如函数名)只是另一个expression primary,调用的参数只是更多的表达式。

注意:此规则有一个例外。当在调用中使用*expression 时(扩展一个可迭代对象以形成额外的位置参数),那么这个表达式在任何关键字参数表达式之前被评估

>>> from itertools import count
>>> def bar(n, r=(), c=count()): print(f'{next(c)}: bar({n!r})'); return r
...
>>> def foo(*args, **kwargs): pass
...
>>> foo(bar('a1'), spam=bar('a2'), *bar('varargs'), **bar('kwargs', {}))
0: bar('a1')
1: bar('varargs')
2: bar('a2')
3: bar('kwargs')

链接的文档指出:

这样做的结果是,尽管*expression 语法可能出现在显式关键字参数之后,但它会在关键字参数之前处理[.]

【讨论】:

  • 这是一个比另一个更好的答案,指出可以在语言参考中找到它。另一个只是表明它是这样的,但它并不能证明它应该总是这样。
【解决方案2】:

是的,Python 总是从左到右计算函数参数。

据我所知,这适用于任何逗号分隔的列表:

>>> from __future__ import print_function
>>> def f(x, y): pass
...
>>> f(print(1), print(2))
1
2
>>> [print(1), print(2)]
1
2
[None, None]
>>> {1:print(1), 2:print(2)}
1
2
{1: None, 2: None}
>>> def f(x=print(1), y=print(2)): pass
...
1
2

【讨论】:

  • 很遗憾,示例无法证明这不是未定义的行为
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-05
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
  • 2013-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多