![](/img/trans.png)
[英]Quick question on error in python list * a constant e.g. [a , b, c, d , e ] * x
[英]Why isn't assigning to an empty list (e.g. [] = "") an error?
在 python 3.4 中,我正在輸入
[] = ""
它工作正常,沒有引發異常。 雖然當然[]
不等於之后的""
。
[] = ()
也工作正常。
"" = []
雖然按預期引發異常,
() = ""
雖然按預期引發異常。 發生什么了?
你不是為了平等而比較。 您正在分配.
Python 允許您分配給多個目標:
foo, bar = 1, 2
將這兩個值分別分配給foo
和bar
。 您所需要的只是右側的序列或可迭代對象,以及左側的名稱列表或元組。
當你這樣做時:
[] = ""
您為空的名稱列表分配了一個空序列(空字符串仍然是序列)。
它與做的事情本質上是一樣的:
[foo, bar, baz] = "abc"
你最終得到foo = "a"
, bar = "b"
和baz = "c"
,但字符更少。
但是,您不能分配給字符串,因此分配左側的""
永遠不起作用,並且始終是語法錯誤。
請參閱賦值語句文檔:
賦值語句評估表達式列表(請記住,這可以是單個表達式或逗號分隔的列表,后者產生一個元組)並將單個結果對象從左到右分配給每個目標列表。
和
將對象分配給目標列表,可選擇括在圓括號或方括號中,遞歸定義如下。
強調我的。
Python 不會為空列表拋出語法錯誤實際上是一個錯誤! 官方記錄的語法不允許空的目標列表,對於空的()
你確實會得到一個錯誤。 見錯誤 23275 ; 它被認為是一個無害的錯誤:
出發點是認識到這已經存在很長時間並且是無害的。
它遵循文檔中的賦值語句部分規則,
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
如果
target list
是一個逗號分隔的目標列表:對象必須是一個可迭代對象,其項目數與目標列表中的目標數量相同,並且項目從左到右分配給相應的目標。對象必須是一個序列,其項目數與目標列表中的目標數量相同,並且項目從左到右分配給相應的目標。
所以,當你說
[] = ""
""
是一個可迭代的(任何有效的 python 字符串都是一個可迭代的),並且它正在被解包到列表的元素上。
例如,
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
由於您有一個空字符串和一個空列表,因此無需解包。 所以,沒有錯誤。
但是,試試這個
>>> [] = "1"
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack
在[] = "1"
情況下,您試圖將字符串"1"
解壓到一個空的變量列表上。 所以它抱怨“解包的值太多(預期為 0)”。
同樣,在[a] = ""
情況下,您有一個空字符串,因此實際上沒有什么可解壓的,但是您將它解壓到一個變量上,這又是不可能的。 這就是為什么它抱怨“需要超過 0 個值才能解包”。
除此之外,正如你所注意到的,
>>> [] = ()
也不會拋出錯誤,因為()
是一個空元組。
>>> ()
()
>>> type(())
<class 'tuple'>
當它在一個空列表上解包時,沒有什么可以解包的。 所以沒有錯誤。
但是,當你這樣做
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can't assign to literal
正如錯誤消息所說,您正在嘗試分配給字符串文字。 這是不可能的。 這就是為什么你會收到錯誤。 就像在說
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
內件
在內部,這個賦值操作會被翻譯成UNPACK_SEQUENCE
操作碼,
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
這里,由於字符串為空, UNPACK_SEQUENCE
解包0
次。 但是當你有這樣的事情
>>> dis(compile('[a, b, c] = "123"', "string", "exec"))
1 0 LOAD_CONST 0 ('123')
3 UNPACK_SEQUENCE 3
6 STORE_NAME 0 (a)
9 STORE_NAME 1 (b)
12 STORE_NAME 2 (c)
15 LOAD_CONST 1 (None)
18 RETURN_VALUE
序列123
從右到左解壓到堆棧中。 因此,堆棧的頂部將是1
,下一個將是2
,最后一個將是3
。 然后它從棧頂開始將左側表達式中的變量一一賦值。
順便說一句,在 Python 中,這就是您可以在同一個表達式中進行多個賦值的方式。 例如,
a, b, c, d, e, f = u, v, w, x, y, z
這是有效的,因為右側的值用於構造一個元組,然后它將在左側的值上解包。
>>> dis(compile('a, b, c, d, e, f = u, v, w, x, y, z', "string", "exec"))
1 0 LOAD_NAME 0 (u)
3 LOAD_NAME 1 (v)
6 LOAD_NAME 2 (w)
9 LOAD_NAME 3 (x)
12 LOAD_NAME 4 (y)
15 LOAD_NAME 5 (z)
18 BUILD_TUPLE 6
21 UNPACK_SEQUENCE 6
24 STORE_NAME 6 (a)
27 STORE_NAME 7 (b)
30 STORE_NAME 8 (c)
33 STORE_NAME 9 (d)
36 STORE_NAME 10 (e)
39 STORE_NAME 11 (f)
42 LOAD_CONST 0 (None)
45 RETURN_VALUE
但是經典的交換技術a, b = b, a
使用堆棧頂部元素的旋轉。 如果你只有兩個或三個元素,那么它們會被特殊的ROT_TWO
和ROT_THREE
指令處理,而不是構造元組ROT_THREE
包。
>>> dis(compile('a, b = b, a', "string", "exec"))
1 0 LOAD_NAME 0 (b)
3 LOAD_NAME 1 (a)
6 ROT_TWO
7 STORE_NAME 1 (a)
10 STORE_NAME 0 (b)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.