2012-09-30 164 views
14

我正在寫一個解析器,並在調試它的過程中,我發現,很顯然,這是合法的Python:這個Python語句是什麼意思?

for [] in [[]]: print 0 

,所以是這個(!):

for [][:] in [[]]: print 0 

我不要責怪解析器得到困惑... 我是無法弄清楚如何解釋它!

這句話究竟是什麼意思?

+0

谷歌的序列拆封。應該解釋它。 – hendrik

回答

14

在執行方面:沒什麼。

for循環本身循環遍歷空列表,因此不會發生迭代。

這是一件好事,因爲for []表示:將循環中的每個條目分配給0個變量。後半部分可能是你困惑的事情。

該聲明是合法的,因爲target token token_list允許您將序列中的值分配給同樣大的變量名稱序列;我們稱這個元組爲開箱。以下是目標列表的更有用的例子,在分配和刪除:

(a, b, c) = range(3) 
del a, b, c 

你可以做同樣的for循環:

nested = [[1,2,3], [4,5,6]] 
for a, b, c in nested: 
    print nested 

:您可以使用元組和列表的target_list令牌,這也是合法的:

[a, b] = (1, 2) 

但是,在Python中,列表可以是空的。因此,下面是合法的,但無意義的:

[] = [] 

最後,所以是這樣的:

nested_empty = [[], [], []] 
for [] in nested_empty: 
    pass 

多與目標列表樂趣:

[][:] = [1, 2, 3] 

現在左手邊在分配中使用切片。從文檔:

如果目標是切片:評估引用中的主表達式。它應該產生一個可變的序列對象(如列表)。分配的對象應該是同一類型的序列對象。接下來,評估下限和上限表達式,只要它們存在;默認值是零和序列的長度。邊界應該評估爲(小)整數。如果任一邊界是負數,則將序列的長度添加到它。結果邊界被限制在零和序列長度之間,包括邊界在內。最後,序列對象被要求用指定序列的項目替換片段。切片的長度可能與指定序列的長度不同,因此如果對象允許,則會更改目標序列的長度。

所以在這裏我們不再使用元組拆包;相反,我們用左側列表替換左側列表的一部分。但是因爲在我們的例子中,左邊的列表是一個匿名列表文字,所得到的修改列表再次丟失。

但是因爲這樣的分配也是一個for循環的法律,以下是合法的語法,雖然比較無意義的:

for [][:] in [range(i) for i in range(10)]: print 0 
+0

啊,這就解釋了爲什麼'[] []]:print 0'中的[] []有效,但[[]]:print 0'中的[] [:]怎麼辦?那是合法的/這是什麼意思? – Mehrdad

+2

該列表不是空的。它包含一個元素,它是空的列表。因此,0將被打印。 –

+0

@Mehrdad:左側的'target_list'可以是一個切片分配。 'alist [1:2]'= somelist'用'somelist'的值替換'[1:2]'指示的片段。因此,切片是一個有效的左側表達式,並且在循環中也是有效的。 –

1
for [] in [[]]: print 0 

它相當於:

In [44]: for [x,y] in [[1,2],[3,4],[5,6]]: # or even (x,y) will work 
    print x,y 
    ....:  
    ....:  
1 2 
3 4 
5 6 

,但前者預計沒有值從列表返回,即,列表中的值是空的或它們的值爲len() i s 0

您不能在那裏使用(),因爲它不是一個有效的。

因爲在Python中,你可以人工肝分配是這樣的:

In [56]: x,y=[1,2]  #this means that the expression on RHS should return two values 
         # (x,y)=[1,2] or x,y=(1,2) or (x,y)=(1,2) all are valid 

In [57]: x 
Out[57]: 1 

In [58]: y 
Out[58]: 2 


In [62]: x,y='ab'  #assign a to x and b to y 

In [63]: x 
Out[63]: 'a' 

In [64]: y 
Out[64]: 'b' 
1

這是我最好的猜測:

for [] in [[]]手段「爲[]每個實例(空列表對象)在此列表[[]](一個列表中只有一個元素,它是一個空列表對象),print 0

在第二種情況下,我認爲[:]將只調用slice() w所有的默認值,這將只是整個列表的一部分。在內部可能會做某些事情,例如創建列表對象的副本,但在這種情況下的效果應該是相同的。

+0

注意:因爲我沒有在這臺機器上訪問Python,所以我將這個猜測基於Skulpt的結果,結果打印出'0'。我假設Skulpt(http://www.skulpt.org/)正在做CPython的同樣的事情,在這個角落案例中這不一定是一個安全的假設。 –

1

的for..in結合結構在Python手冊

http://docs.python.org/reference/compound_stmts.html#the-for-statement

描述可以有多個變量的in關鍵字左側

for [i,j] in [(1,2),(3,4),(5,6)]: 
    print i, j 

for [i,j] in [[1,2],[3,4],[5,6]]: 
    print i, j 

手動說,這是像

i,j = (1,2) 

爲第一次迭代等。因此,您可以擁有一個空變量列表,因爲迭代列表只有一個空列表作爲唯一元素。該循環將打印0一次。

您正在閱讀的解析器是否自動生成?這種說法可以由非人類來源產生。我沒有看到它的目的。

+0

重要的部分是手冊中的「target」原子,它定義了一個左手邊的法律表達式。 –

1
for [] in [[]]: print 0 

意味着,在[[]]每個空iterables,那就是它包含一個空的列表清單,打印0它不僅侷限於名單,但每iterables可以投入這一點。例如,您可以嘗試:

# empty list, empty tuple, empty string, empty unicode 
for [] in [[],(), '', unicode()]: print 0 

並且它會打印0四次。

[] [:]與[]相同。它會返回一個空的列表,所以我的答案和上面一樣。

0

假設你有一個元組列表,看起來像這樣:

L = [(1,2), (3,4), (5,6)] 

假設你想在一些特殊的方式來打印這些元組:

for tup in L: 
    a = tup[0] 
    b = tup[1] 
    if a<b: 
     print a,b 
    else: 
     print b,a 

但分配ab明確要tup的內容相當繁瑣。所以,你可以這樣做:

for tup in L: 
    a,b = tup 
    if a<b: 
     print a,b 
    else: 
     print b,a 

但是你可以讓它變得不那麼單調乏味:

for (a,b) in L: # you could also do "for [a,b] in L" 
    if a<b: 
     print a,b 
    else: 
     print b,a 

這裏,(a,b)模式對由迭代中返回的元素相匹配。在for循環的第一次執行,該元件通過迭代中返回是(1,2),它得到的樣式反對(a,b)匹配,因此其分配1a2b

現在,在你的第一個例子,你迭代一個包含一個空列表的列表。這意味着您正試圖打印儘可能多的0 s,因爲此列表中有[] s。但它比這更復雜一點:

當你嘗試模式匹配,如我的第三個例子,python遍歷變量和迭代器返回的元素的列表(或元組),同時,分配值,因爲他們走。所以當你的模式不包含變量時,你試圖模式匹配的元素也應該是空的(並且可迭代的)。這解釋了以下行爲:

>>> for i in 5: print i 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

>>> for [] in [[], 5]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

...而這種行爲太:

>>> x,y = (2,5,3) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

>>> for [] in [[], [5]]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

現在,作爲你的第二個例子中,[:]操作基本上創建列表的副本它被呼叫,以便更改原始列表不會改變副本,反之亦然:

>>> L = [1,2,3] 
>>> M = L 
>>> M[0] = 'a' 
>>> print L[0] 
'a' 

>>> L = [1,2,3] 
>>> M = L[:] 
>>> M[0] = 'a' 
>>> print L[0] 
1 

所以,當你調用[][:],你正在做的是做一個新的空單,其工作一樣我解釋你的第一個例子