7

我最近一直在尝试使用 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
4

3 回答 3

20

这与生成器没有任何关系:

>>> 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作为参数的操作在%.

于 2012-08-07T14:12:19.940 回答
8

Python 的操作顺序是从左到右,除了 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

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

更新:在二元算术运算下的同一文档中,它说明了一些明显的含义,但内涵相关:

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

虽然这似乎只是告诉您%运算符的作用,但我认为它的位置和上下文也告诉您它具有相同的优先级,无论它是用作modulo还是interpolate

于 2012-08-07T14:21:29.633 回答
5

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

意外的行为:

>>> '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是在字符串格式化之前执行的%。如果乘法可以先于字符串格式化,并且字符串格式化先于乘法,则它们的优先级必须相等。

于 2012-08-07T14:34:15.443 回答