web-dev-qa-db-ja.com

Pythonと呼ばれるこの種の代入は何ですか?a = b = True

Tuple unpacking について知っていますが、1行に複数の等号がある場合、この割り当ては何と呼ばれますか?アラa = b = True

特にRHSが変更可能である場合は常に少しつまずきますが、ドキュメントで検索する適切なキーワードを見つけるのに本当に苦労しています。

30
pfctdayelise

それは一連の割り当てであり、それを説明するために使用される用語は...

-ロールロールを頂けますか?

連鎖代入


私はそれをかなりグーグルで実行しましたが、おそらくほとんどの人がそれを使用するのは非常に簡単だと思っているので、トピックについて読むことはそれほど多くないことがわかりました(そして本当のオタクだけがトピックについてもっと知りたいです) 。


前の式では、評価の順序は、右端の=から始まり、左に向かって進むと見なすことができます。これは、次のように書くのと同じです。

b = True
a = b

上記の順序は、ほとんどの言語が割り当てチェーンを表すものですが、pythonは、異なる方法で行います。Inpython =式は、以下の同等のものとして評価されますが、前述の結果以外の結果にはなりません。

temporary_expr_result = True

a = temporary_expr_result
b = temporary_expr_result

スタックオーバーフローについては、こちらをご覧ください。

49

OK、「連鎖割り当て」は私が探していた検索用語でしたが、もう少し掘り下げた後、厳密には正しくないと思います。ただし、「代入ステートメントの特殊なケース」よりも検索が簡単です。

ウィキペディアの記事送信者 リンク先:

Pythonでは、代入ステートメントは式ではないため、値を返しません。代わりに、連鎖割り当ては、単一の式に対して複数のターゲットを持つ一連のステートメントです。割り当ては左から右に実行されるため、i = arr[i] = f()は式f()を評価し、その結果を左端のターゲットiに割り当ててから、同じものを割り当てます。 iの新しい値を使用して、次のターゲットarr[i]に結果を返します。

別の ブログ投稿 は言う:

Pythonでは、代入ステートメントは値を返しません。連鎖代入(より正確には、連鎖代入ステートメントのように見えるコード)は、代入ステートメントの特殊なケースとして認識され、サポートされます。

これは私にとって最も正しいように思われます。 ドキュメント -特に(target_list "=")+-をよく読んでください。

割り当てステートメントは、式リスト...を評価し、結果の1つのオブジェクトを各ターゲットリストに左から右に割り当てます。

したがって、実際には「右端から左に評価」されるわけではありません。RHSが評価されてから、左端のターゲットから右に割り当てられます。実際の(または考案された)例を考えることはできません。差。

7
pfctdayelise

@refpの答えは、dis(逆アセンブリ)モジュールを使用したこの出力でさらにサポートされます。

_>>> def a(x):
...   g = h = x
...
>>> import dis
>>> dis.dis(a)
  2           0 LOAD_FAST                0 (x)
              3 DUP_TOP
              4 STORE_FAST               1 (g)
              7 STORE_FAST               2 (h)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE
_

RHSが取得されて複製され、宛先変数に左から右に格納されます(_e = f = g = h = x_を使用して自分で試してください)。

RHSがa = b = fn()のような関数呼び出しである場合、他のいくつかのポスターは混乱しています。RHSは一度だけ評価され、結果は連続する各変数に割り当てられます。これにより、戻り値がリストやdictなどの可変である場合、不要な共有が発生する可能性があります。

threadingを使用している場合は、複数の明示的な代入ステートメントに対する連鎖代入フォームによって暗示される「原子性」がないことに注意してください。gとhへの代入と、別のスレッドの間でスレッドの切り替えが発生する可能性があります。それらの2つを見ると、2つの変数に異なる値が表示される可能性があります。

ドキュメント、7.2。割り当てステートメント から、ghは2つのターゲットリストx式リストです:

_assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)
_

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

6
PaulMcG

私の無知のために、今日pythonのChainedAssignmentに噛まれました。コードで

if l1.val <= l2.val:
    tail = tail.next = l1 # this line 
    l1 = l1.next

私が期待したのは

tail.next = l1
tail = tail.next
# or equivalently 
# tail = l1

リストに自己ループを生成する以下になりましたが、無限ループに陥りました。

tail = l1
tail.next = l1 # now l1.next is changed to l1 itself

a = b = cの場合、一方向(Pythonなど)は

tmp = evaluate(c)
evaluate(a) = tmp
evaluate(b) = tmp

そして、2つの代入に対して等しい右オペランドを持ちます。

もう1つ(C++など)は

evaluate(b) = evaluate(c)
evaluate(a) = evaluate(b)

この場合はa = b = cは基本的に

b = c
a = b

また、2つの右側のオペランドは異なる可能性があります。

そのため、同様のコードがC++でうまく機能します。

3
qeatzy