2012-08-07 90 views
7

我最近一直在尝试使用python生成器,我遇到以下好奇的行为,并且我很好奇为什么会发生这种情况以及发生了什么: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 
+1

旁白:如果你真的格式的整数,使用'%D','没有%s'。 – kojiro 2012-08-07 14:22:59

+5

或者拥抱新的'format'语法。我第一次看到它时觉得有点长,但我越来越喜欢它。 – DSM 2012-08-07 14:29:49

+0

作为一个同事曾经告诉我,*总是*%' – chepner 2012-08-07 14:29:59

回答

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可以工作,因为在%之前会评估和2作为参数的**

+0

很快! – jamylak 2012-08-07 14:12:56

+2

你打我吧...勉强:P – 2012-08-07 14:13:23

+0

非常有趣,感谢您的快速反应 - 我仍然需要等待11分钟才能标记为接受。由于不相关,我删除了生成器和收益的标签。 – 2012-08-07 14:13:45

8

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它指出denotatively明显,但内涵式相关的事情:

...%操作也由字符串和Unicode对象超载 执行字符串格式(也称为插值)。

虽然这看起来只是告诉你什么%操作确实,我认为它的位置和环境还告诉你它具有相同的优先级是否它作为插值

+2

该文档末尾的总结更加明确地说明 - 特别是,脚注8表示:“'%'操作符也用于字符串格式化;应用相同的优先级”。 – lvc 2012-08-07 14:54:17

+0

想象一下,如果不是这样的话......在知道子表达式的运行时类型之前,您将无法解析Python代码! – Aaron 2013-02-05 09:03:32

+0

@Aaron *如果他们不像他们那样,情况会大不相同。* - [Anna Russell](http://en.wikipedia.org/wiki/Anna_Russell)。如果python需要type [annotations](http://www.python.org/dev/peps/pep-3107/)并用于在编译时强制执行类型,则它将是一种不同的语言,但不是一个疯狂的想法。 :) – kojiro 2013-02-05 15:12:25

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