web-dev-qa-db-ja.com

空のリスト([] = ""など)にエラーが割り当てられないのはなぜですか?

python 3.4、私は入力しています

[] = "" 

正常に機能し、例外は発生しません。もちろん[]はその後""と等しくありませんが。

[] = ()

また、正常に動作します。

"" = []

ただし、予想どおりに例外が発生します。

() = ""

ただし、予想どおりに例外が発生します。どうしたの?

110
Vardd

あなたは平等を比較していません。あなたはassigningです。

Pythonでは、複数のターゲットに割り当てることができます。

foo, bar = 1, 2

2つの値をそれぞれfoobarに割り当てます。必要なのは、右側にsequenceまたはiterableがあり、左側に名前のリストまたはタプルがあります。

行うとき:

[] = ""

名前の空のリストにemptyシーケンス(空の文字列はまだシーケンス)を割り当てました。

これは、基本的に同じことです:

[foo, bar, baz] = "abc"

foo = "a"bar = "b"、およびbaz = "c"になりますが、文字数は少なくなります。

ただし、文字列に割り当てることはできないため、割り当ての左側の""は機能せず、常に構文エラーになります。

割り当てステートメントドキュメント を参照してください:

割り当てステートメントは、式リストを評価し(これは単一の式またはコンマ区切りのリストであり、後者はタプルを生成することに注意してください)、単一の結果オブジェクトを左から右に各ターゲットリストに割り当てます。

そして

オブジェクトのターゲットリストへの割り当て括弧または角括弧でオプションで囲まれたものは、次のように再帰的に定義されます。

エンファシス鉱山

つまり、Pythonは空のリストに対して構文エラーをスローしません。実際には少しバグです!公式に文書化された文法では、空のターゲットリストおよび空の()エラーが発生します bug 23275 を参照してください;これは無害なバグと見なされます:

出発点は、これが非常に長い間存在しており、無害であることを認識することです。

空のリストには割り当てるが空のタプルには割り当てないのはなぜですか? も参照してください

132
Martijn Pieters

それは、ドキュメントの Assignment statementセクション ルールに従います。

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] = ""の場合、空の文字列があるため、実際にアンパックするものはありませんが、1つの変数でアンパックしていますが、これも不可能です。それが「アンパックするのに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 opコードに変換されます。

>>> dis(compile('[] = ""', "string", "exec"))
  1           0 LOAD_CONST               0 ('')
              3 UNPACK_SEQUENCE          0
              6 LOAD_CONST               1 (None)

ここでは、文字列が空なので、UNPACK_SEQUENCE0回アンパックします。しかし、あなたがこのようなものを持っているとき

>>> 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です。次に、スタックの最上部から左側の式の変数に1つずつ割り当てます。


ところで、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は、スタックの最上部にある要素の回転を使用します。要素が2つまたは3つしかない場合、タプルを構築して展開する代わりに、特別な ROT_TWO および 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
36
thefourtheye