簡體   English   中英

為什么分配給空列表(例如 [] = "")不是錯誤?

[英]Why isn't assigning to an empty list (e.g. [] = "") an error?

在 python 3.4 中,我正在輸入

[] = "" 

它工作正常,沒有引發異常。 雖然當然[]不等於之后的""

[] = ()

也工作正常。

"" = []

雖然按預期引發異常,

() = ""

雖然按預期引發異常。 發生什么了?

你不是為了平等而比較。 您正在分配.

Python 允許您分配給多個目標:

foo, bar = 1, 2

將這兩個值分別分配給foobar 您所需要的只是右側的序列可迭代對象,以及左側的名稱列表或元組。

當你這樣做時:

[] = ""

您為的名稱列表分配了一個序列(空字符串仍然是序列)。

它與做的事情本質上是一樣的:

[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_TWOROT_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM