3

Pythonで4つの変数[a=1、b = 2、c = 3、d = 0]を宣言し、「、」、「=」(単純代入演算子)を使用して1行のコードでそれらを交換しました。

複数の回答があり、混乱しています。私を助けてください...

ケース1:

a=1
b=2
c=3
d=0
a=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)

ケース1の出力:

a = 2
b = 3
c = 3
d = 0


ケース2:

a=1
b=2
c=3
d=0
b=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)

ケース2の出力:

a = 2
b = 3
c = 3
d = 0


ケース3:

a=1
b=2
c=3
d=0
c=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)

ケース3の出力:

a = 2
b = 3
c = (2,3)
d = 0


ケース4:

a=1
b=2
c=3
d=0
d=a,b=b,c
print "a = " + str(a)
print "b = " + str(b)
print "c = " + str(c)
print "d = " + str(d)

ケース4の出力:

a = 2
b = 3
c = 3
d = (2,3)

混乱は次のとおりです。

ケース番号3と4の場合、出力は正しいです(私が期待したように)。しかし、番号1と2の場合、aの値は2で、bの値は3です。値は(2,3)になるはずです。では、私のコードの何が問題なのでしょうか?

[私のPythonバージョンは2.7です]

4

1 に答える 1

13

tl; dr:複数の割り当て(=1行に複数のステートメント)は、右から左ではなく、左から右に評価されます(右側の式を評価した後)。

問題を複雑にするために、タプル割り当てと「通常の」割り当てを強力な組み合わせで使用しています。

タプル代入は1つの代入演算子を使用するため、2つの変数を交換するには、次を使用します。

a, b = b, a

右側は、左側にある変数と同じ数の要素のタプルに評価される必要があります。あなたはそれをするので、それは大丈夫です。

さて、あなたの例では、タプルを解凍するだけではありません。左側に変数が1つしかない場合、タプルは解凍されず、単に割り当てられます。

a, b = 1, 2
a = b, a

になり(2, 1)ます。

同じ行で複数の割り当てを使用すると、楽しみが始まります。これらは左から右に処理されます。

したがって、次の簡単な例:

a = b = c = 1

a、、、、、のようになること1を意味しbますc

これで、それぞれのケースを理解できます。

  1. a=a,b=b,c、ここa = 1b = 2、、、c = 3

    これは次のようになります:evaluate- b, c> 、次にそれを->(2, 3)に割り当てます。次に、それを、、、、に割り当てます。結果:、、。aa = (2, 3)a, ba = 2b = 3a = 2b = 3c = 3

  2. b=a,b=b,c、ここa = 1b = 2、、、c = 3

    前の場合と同じですが、b = (2, 3)最初に設定され、次にb = 3再び、ケース1と同じ結果が設定されます。

  3. c=a,b=b,c、ここa = 1b = 2、、、c = 3

    ケース1と2と同じように右側に入力しますが、最初にを設定しc = (2, 3)ます。期待どおりの最終結果a = 2、、、。b = 3c = (2, 3)

  4. d=a,b=b,c、ここa = 1b = 2、、、c = 3

    ケース3と同じですが、d代わりに設定します。驚く様な事じゃない。

ここで混乱しているのは、右側が評価された後、割り当てが右から左ではなく、左から右に処理されることです。

このような場合、実際には、Pythonバイトコードを逆アセンブルするdis.dis()関数を介して(関数にラップされた)コードを実行するのが最も簡単です。

>>> import dis
>>> def f(): a=a,b=b,c
... 
>>> dis.dis(f)
  1           0 LOAD_FAST                0 (b)
              3 LOAD_GLOBAL              0 (c)
              6 BUILD_TUPLE              2
              9 DUP_TOP             
             10 STORE_FAST               1 (a)
             13 UNPACK_SEQUENCE          2
             16 STORE_FAST               1 (a)
             19 STORE_FAST               0 (b)
             22 LOAD_CONST               0 (None)
             25 RETURN_VALUE        

これは最初のケースです。BUILD_TUPLEDUP_TOPオペコード(後者は追加の割り当てを提供するためにスタックに追加のコピーを作成します)の後、最初に行われるのは、のSTORE_FAST操作でaあり、その後にUNPACK_SEQUENCE(タプル割り当てオペコード)が続き、結果をに格納する方法に注意してください。aおよびb

于 2012-12-01T08:20:05.837 に答える