2016-10-26 19 views
2
>>> i = 1 
>>> A = [3,4,-1,1] 
>>> A[A[i] - 1], A[i] = A[i], A[A[i] - 1] 
>>> A 
[3, 1, -1, 4] 
>>> A = [3,4,-1,1] 
>>> A[i], A[A[i] - 1] = A[A[i] - 1], A[i] 
>>> A 
[4, 1, -1, 1] 

リストの複数の変数の代入を行うときに質問があります。上記の例のように 、割り当てPythonの複数割り当て問題(リスト)

A[A[i] - 1], A[i] = A[i], A[A[i] - 1] 

は、私は本当にPythonで内部の計算順序を混乱してい割り当て

A[i], A[A[i] - 1] = A[A[i] - 1], A[i] 

は異なっています。なぜ結果が違うのですか?このような複数の割り当てを1行で行う最良の方法は何ですか?

+0

@Prune:そこでの答えは、この質問に現れる課題間の干渉の種類については論じません。 – user2357112

+2

私はちょうどそれを同じ論理シーケンスに分解し、ユーザーの問題を再現しました。要するに、私は同じインタラクションを得ました。 – Prune

+0

@プルーン:私はそうではないと答えたものがありますか?割り当てや評価がLHSにどのようにインタリーブされているか、それがどのように割り当てを互いに干渉させることができるかについては何も言わない。 – user2357112

答えて

0

動作のシーケンスは、任意の複数の割り当てのために同じに動作:

  1. RHS(右側)上のすべての発現は、一時的変数にそれぞれ配置し、左から右に評価します。
  2. 左から右へのLHS(左)の式を評価します。これらのそれぞれについて、対応する一時変数をRHSから割り当てます。 [i]は各シーケンスに変更されますとき

    # A[A[i] - 1], A[i] = A[i], A[A[i] - 1] 
    A = [3,4,-1,1] 
    t1 = A[i] 
    t2 = A[A[i] - 1] 
    # t1 = 4, t2 = 1 
    A[A[i] - 1] = t1 
    A[i] = t2 
    print A 
    # Result: [3, 1, -1, 4] 
    
    # A[i], A[A[i] - 1] = A[A[i] - 1], A[i] 
    A = [3,4,-1,1] 
    t2 = A[A[i] - 1] 
    t1 = A[i] 
    # As before, t1 = 4, t2 = 1 
    A[i] = t2 
    # A[i] is now 1 ! 
    A[A[i] - 1] = t1 
    print A 
    # Result: [4, 1, -1, 1] 
    

    決定的な違いがある:あなたのコードの場合

が、これはに展開されます。 2番目の例では、最後の割り当てでA [A [i] - 1]を評価すると、A [i]はすでに1に変更されています。したがって、この最後の割り当ては、 3.

1

a, b = b, a+bのようにすることをお勧めする場合、このような複数の割り当ては、ある割り当てが別の割り当てを妨害する問題を常に回避すると考えられます。特に、すべての式の評価がどの割り当てよりも先に行われると考えるのは当然です。残念ながら、それはどのように動作するのではありません。

フォーム

expr_a[expr_b], expr_c[expr_d] = expr_e, expr_f 

の複数の割り当てを持っている場合は、次のようにイベントの順序が行く:

  1. expr_eexpr_fを評価し、右辺を評価します。
  2. expr_aexpr_bと評価された最初の割り当てを実行します。
  3. 3番目の割り当てを実行し、expr_cexpr_dと評価します。 これらの式が評価されると、最初の割り当てがすでに行われています。 expr_a[expr_b]に代入する第二の割り当てに何が起こるか変わるexpr_c又はexpr_dの値を変更した場合を意味

A[i]に割り当てると、割り当て先A[A[i] - 1]A[i] - 1の値が変更されます。


このような場合は、複数の割り当てを使用しないでください。割り当てを独自の行に分け、必要に応じて一時変数を使用して、割り当てによって変更される値を記憶します。 the documentationパー

3

Pythonは左から右に式を評価します。割り当てを評価する の間に、右側は の左側の前に評価されます。

詳細は、this sectionを参照してください。この行動を利用した脳ティーザーの良い例がありますhere

これは、=の右辺が最初に左から右に評価され、次に左から右への割り当てが行われることを意味します。必然的に、角括弧はインサイドアウトで評価されます。 、左側に左側のターゲットへの割り当てはAの内容を変更

i = 1 
A = [3, 4, -1, 1] 

A[i], A[A[i] - 1] = A[A[i] - 1], A[i] 
        = A[A[1] - 1], A[i] 
        = A[4 - 1], A[i] 
        = A[3], A[i] 
        = 1, A[i] 
        = 1, A[1] 
        = 1, 4 
A[i], A[A[i] - 1] = 1, 4 
A[1], A[A[i] - 1] = 1, 4 # A becomes [3, 1, -1, 1] 
A[A[1] - 1] = 4 
A[1 - 1] = 4 
A[0] = 4 # A becomes [4, 1, -1, 1] 

た:

i = 1 
A = [3, 4, -1, 1] 

A[A[i] - 1], A[i] = A[i], A[A[i] - 1] 
        = A[1], A[A[i] - 1] 
        = 4, A[A[i] - 1] 
        = 4, A[A[1] - 1] 
        = 4, A[4 - 1] 
        = 4, A[3] 
        = 4, 1 
A[A[i] - 1], A[i] = 4, 1 
A[A[1] - 1], A[i] = 4, 1 
A[4 - 1], A[i] = 4, 1 
A[3], A[i] = 4, 1 # A becomes [3, 4, -1, 4] 
A[i] = 1 
A[1] = 1 # A becomes [3, 1, -1, 4] 

そして、ここでは、第二のだ:段階的にそれを破壊、ここでは最初の例です右側のターゲットの索引付けを変更します。 4は、A[1]4からに変更)の値に応じて、A[3]またはA[0]のいずれかに割り当てられます。

「このような複数の割り当てを1行で行うにはどうすればよいですか?」 - 私はそれを避けるために最善を尽くします。私はこのような動くターゲットに割り当てる必要がある状況は考えられません。

+0

A.swap(i、A [i] -1)を書くことができれば、1つのライナーは...多分このようなスワップ機能がない理由は、この複数の割り当て機能です。https://www.reddit.com/r/Python/comments/3eh5p3/why_isnt_there_a_listswapi_j_function_built_in_to/ –

+0

@ aka.niceで仮定されているように、 'A [i] - 1'は関数が呼び出される前に評価され、代入の両側 – jonrsharpe

+0

はい、A [i] -1をtemp(またはスタック)に暗黙的にプッシュすることは、式を対称的に動作させるものです。A.swap(A [i] -1、i) –