2012-08-07 71 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的原因。如果乘法可以在字符串格式化之前進行,並且字符串格式化在乘法之前,則它們的優先級必須相等。