私はそれが何をするのか理解しようとしていくつかの古いコードを調べています、そして私はこの奇妙な文に出くわしました:
*x ,= p
p
は、このコンテキストのリストです。私はこの声明が何をしているのかを理解しようとしてきました。私が知る限り、x
をp
の値に設定するだけです。例えば:
p = [1,2]
*x ,= p
print(x)
与えるだけ
[1, 2]
これはx = p
とは違うのですか?この構文が何をしているのか考えていますか?
_*x ,= p
_は基本的にx = list(p)
の難読化されたバージョンで、 拡張反復可能アンパック を使用します。 x
の後のコンマは、割り当てターゲットをタプルにするために必要です(ただし、リストにすることもできます)。
_*x, = p
_isは_x = p
_とは異なります。前者はp
の-copyを作成するためです(つまり、新しいリスト)後者は、元のリストに対してreferenceを作成します。説明する:
_>>> p = [1, 2]
>>> *x, = p
>>> x == p
True
>>> x is p
False
>>> x = p
>>> x == p
True
>>> x is p
True
_
これは、Python 3.0( PEP 3132 )で導入された機能です。Python 2では、次のようなことができます。
>>> p = [1, 2, 3]
>>> q, r, s = p
>>> q
1
>>> r
2
>>> s
3
Python 3はこれを拡張して、1つの変数が複数の値を保持できるようにしました。
>>> p = [1, 2, 3]
>>> q, *r = p
>>> q
1
>>> r
[2, 3]
したがって、これがここで使用されています。ただし、3つの値を保持する2つの変数の代わりに、リスト内の各値を取るのは1つの変数だけです。 x = p
は、x
がp
の別の名前であることを意味するだけなので、x = p
とは異なります。ただし、この場合は、たまたま同じ値を持つ新しいリストです。 (興味があるかもしれません "Least Astonishment" and Mutable Default Argument )
この効果を生成する他の2つの一般的な方法は次のとおりです。
>>> x = list(p)
そして
>>> x = p[:]
Python 3.3であるため、リストオブジェクトには実際にコピーを目的としたメソッドがあります。
x = p.copy()
スライスは実際には非常によく似た概念です。ただし、nneonneoが指摘したように、これはスライスやスライスをサポートするタプルなどのオブジェクトでのみ機能します。ただし、あなたが言及した方法は、イテレート可能なすべてのディクショナリ、セット、ジェネレータなどで機能します。
これらは常に dis
にスローして、何がスローバックされるかを確認してください。 *x, = p
が実際にx = p
とどのように異なるかがわかります:
dis('*x, = p')
1 0 LOAD_NAME 0 (p)
2 UNPACK_EX 0
4 STORE_NAME 1 (x)
一方、単純な割り当てステートメント:
dis('x = p')
1 0 LOAD_NAME 0 (p)
2 STORE_NAME 1 (x)
(無関係なNone
リターンを取り除く)
ご覧のとおり、UNPACK_EX
はこれらの間の異なるオペコードです。 文書化されている :
スター付きターゲットを使用して割り当てを実装します。TOS(スタックの最上部)で反復可能オブジェクトを個々の値にアンパックします。値の合計数は反復可能アイテムのアイテム数よりも少なくなります。新しい値の1つはすべてのリストになります残りのアイテム。
Eugeneが指摘したように、既存のオブジェクトへの参照ではなく、x
という名前で参照される新しいオブジェクトを取得するのはそのためです(x = p
の場合)。
*x,
は非常に奇妙に見えます(余分なコンマとすべて)が、ここでは必須です。左側はタプルまたはリストのいずれかでなければなりません。また、Pythonで単一要素のタプルを作成する癖があるため、末尾の,
を使用する必要があります。
i = 1, # one element Tuple
混乱する人が好きなら、いつでもlist
バージョンを使用できます:
[*x] = p
これはまったく同じことを行いますが、余分なコンマがそこにぶら下がっていません。