【问题标题】:Python - curious/unexpected behaviour - precedence of operatorsPython - 好奇/意外的行为 - 运算符的优先级
【发布时间】:2012-08-07 14:10:12
【问题描述】:

我最近一直在尝试使用 python 生成器,我遇到了以下奇怪的行为,我很想了解为什么会发生这种情况以及发生了什么:

def generating_test(n): 
    for a in range(n): 
        yield "a squared is %s" % a*a # Notice instead of a**2 we have written a*a

for asquare in generating_test(3): 
    print asquare 

输出:

a squared is 1
a squared is 2a squared is 2

与生成预期输出的以下脚本相比:

def generating_test(n): 
    for a in range(n): 
        yield "a squared is %s" % a**2 # we use the correct a**2 here

for asquare in generating_test(3): 
    print asquare 

输出:

a squared is 0
a squared is 1
a squared is 4

【问题讨论】:

  • aside:如果您真的要格式化整数,请使用%d,而不是%s
  • 或者采用新的format 语法。我第一次看到它时觉得它有点长,但我已经喜欢它了。
  • 一位同事曾经告诉我,总是在 '%' 之后使用元组
  • @DSM 我同意.format 是最好的,无论如何每个人都应该使用它。

标签: python operator-precedence


【解决方案1】:

这与生成器无关:

>>> a = 2
>>> "a squared is %s" % a
'a squared is 2'
>>> ("a squared is %s" % a)*a
'a squared is 2a squared is 2'
>>> "a squared is %s" % a*a
'a squared is 2a squared is 2'
>>> "a squared is %s" % (a*a)
'a squared is 4'

% 运算在乘法之前执行,使用字符串和第一个 a 作为参数。您的 a**2 有效,因为 **a2 作为参数的操作在 % 之前被评估。

【讨论】:

  • 你打败了我......勉强:P
  • 非常有趣,感谢您的快速响应 - 我仍然需要等待 11 分钟才能标记为已接受。我已经删除了 generators 和 yield 的标签,因为它们不相关。
【解决方案2】:

Python's order of operations 是从左到右的,除了 PEMDAS 应用的地方。字符串插值运算符显然与模和乘法具有相同的优先级,因为如果您颠倒顺序,使插值左侧的乘法优先:

>>> print 3 * "a foo %s" % 'hi'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> print 3 * "a foo %s" % ('hi', 'ho', 'yo')
a foo hia foo hoa foo yo

但是,正如您所展示的,求幂胜过从左到右的顺序。

更新:在 same document under Binary Arithmetic Operations 中,它陈述了一些外延明显但内涵相关的内容:

...% 运算符也被字符串和 unicode 对象重载到 执行字符串格式化(也称为插值)。

虽然这似乎只是告诉你 % 运算符 做了什么,但我认为它的位置和上下文也告诉你它是否具有相同的优先级是否用作 em> 或 插值

【讨论】:

  • 该文档末尾的摘要更明确地说明了这一点 - 特别是脚注 8 说:“% 运算符也用于字符串格式化;同样的优先级适用”。
  • 想象一下,如果不是这样......在您知道子表达式的运行时类型之前,您将无法解析 Python 代码!
  • @Aaron 如果不是原来的样子,情况就会大不相同。Anna Russell。如果 python 需要类型 annotations 并用于在编译时强制类型,那将是一种不同的语言,但不是一个疯狂的想法。 :)
【解决方案3】:

当您观察到意外行为时,请通过将其提炼为最简单的情况来开始您的分析。一个简单的案例会更容易学习和理解。

意外行为:

>>> 'hello %s' % 3 * 2
'hello 3hello 3'

(你期望'hello 6'


我们认为 Python 必须将命令解释为 'hello 3' * 2 而不是 'hello %d' % 6。我们尝试用括号强制第二种解释

>>> "hello %s" % (3*2)
'hello 6'

尤里卡!

我们已经证明字符串格式化运算符% 的优先级高于或等于乘法。我们检查了 Python 文档 - 是的,它证实了这一点 http://docs.python.org/reference/expressions.html#summary

为了确认优先级是否相等,我们可以反过来试一下:

>>> "%d,"*2%(1,2)
'1,2,'

看到逗号 (,) 重复,我们推断乘法 "%d," * 2 是在字符串格式化 % 之前执行的。如果乘法可以在字符串格式化之前,并且字符串格式化在乘法之前,它们的优先级必须相等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 2019-02-02
    • 2011-03-16
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多