我正在寫一個解析器,並在調試它的過程中,我發現,很顯然,這是合法的Python:這個Python語句是什麼意思?
for [] in [[]]: print 0
,所以是這個(!):
for [][:] in [[]]: print 0
我不要責怪解析器得到困惑... 我是無法弄清楚如何解釋它!
這句話究竟是什麼意思?
我正在寫一個解析器,並在調試它的過程中,我發現,很顯然,這是合法的Python:這個Python語句是什麼意思?
for [] in [[]]: print 0
,所以是這個(!):
for [][:] in [[]]: print 0
我不要責怪解析器得到困惑... 我是無法弄清楚如何解釋它!
這句話究竟是什麼意思?
在執行方面:沒什麼。
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
啊,這就解釋了爲什麼'[] []]:print 0'中的[] []有效,但[[]]:print 0'中的[] [:]怎麼辦?那是合法的/這是什麼意思? – Mehrdad
該列表不是空的。它包含一個元素,它是空的列表。因此,0將被打印。 –
@Mehrdad:左側的'target_list'可以是一個切片分配。 'alist [1:2]'= somelist'用'somelist'的值替換'[1:2]'指示的片段。因此,切片是一個有效的左側表達式,並且在循環中也是有效的。 –
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'
這是我最好的猜測:
for [] in [[]]
手段「爲[]
每個實例(空列表對象)在此列表[[]]
(一個列表中只有一個元素,它是一個空列表對象),print 0
。
在第二種情況下,我認爲[:]
將只調用slice()
w所有的默認值,這將只是整個列表的一部分。在內部可能會做某些事情,例如創建列表對象的副本,但在這種情況下的效果應該是相同的。
注意:因爲我沒有在這臺機器上訪問Python,所以我將這個猜測基於Skulpt的結果,結果打印出'0'。我假設Skulpt(http://www.skulpt.org/)正在做CPython的同樣的事情,在這個角落案例中這不一定是一個安全的假設。 –
的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一次。
您正在閱讀的解析器是否自動生成?這種說法可以由非人類來源產生。我沒有看到它的目的。
重要的部分是手冊中的「target」原子,它定義了一個左手邊的法律表達式。 –
for [] in [[]]: print 0
意味着,在[[]]每個空iterables,那就是它包含一個空的列表清單,打印0它不僅侷限於名單,但每iterables可以投入這一點。例如,您可以嘗試:
# empty list, empty tuple, empty string, empty unicode
for [] in [[],(), '', unicode()]: print 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
但分配a
和b
明確要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)
匹配,因此其分配1
到a
和2
到b
現在,在你的第一個例子,你迭代一個包含一個空列表的列表。這意味着您正試圖打印儘可能多的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
所以,當你調用[][:]
,你正在做的是做一個新的空單,其工作一樣我解釋你的第一個例子
谷歌的序列拆封。應該解釋它。 – hendrik