What is this kind of assignment in Python called? a = b = True

前端 未结 4 865
有刺的猬
有刺的猬 2020-11-29 04:20

I know about tuple unpacking but what is this assignment called where you have multiple equals signs on a single line? a la a = b = True

It always trips

相关标签:
4条回答
  • 2020-11-29 05:01

    OK, "chained assignment" was the search term I was after, but after a bit more digging I think it's not strictly correct. but it is easier to search for than "a special case of the assignment statement".

    The Wikipedia article senderle linked to says:

    In Python, assignment statements are not expressions and thus do not return a value. Instead, chained assignments are a series of statements with multiple targets for a single expression. The assignments are executed left-to-right so that i = arr[i] = f() evaluates the expression f(), then assigns the result to the leftmost target, i, and then assigns the same result to the next target, arr[i], using the new value of i.

    Another blog post says:

    In Python, assignment statements do not return a value. Chained assignment (or more precisely, code that looks like chained assignment statements) is recognized and supported as a special case of the assignment statement.

    This seems the most correct to me, on a closer reading of the docs - in particular (target_list "=")+ - which also say

    An assignment statement evaluates the expression list ... and assigns the single resulting object to each of the target lists, from left to right.

    So it's not really "evaluated from right-most to left" - the RHS is evaluated and then assigned from left-most target to right - not that I can think of any real-world (or even contrived) examples where it would make a difference.

    0 讨论(0)
  • 2020-11-29 05:11

    It's a chain of assignments and the term used to describe it is...

    - Could I get a drumroll please?

    Chained Assignment.


    I just gave it a quite google run and found that there isn't that much to read on the topic, probably since most people find it very straight-forward to use (and only the true geeks would like to know more about the topic).


    In the previous expression the order of evaluation can be viewed as starting at the right-most = and then working towards the left, which would be equivalent of writing:

    b = True
    a = b
    

    The above order is what most language describe an assignment-chain, but python does it differently. In python the expression is evaluated as this below equivalent, though it won't result in any other result than what is previously described.

    temporary_expr_result = True
    
    a = temporary_expr_result
    b = temporary_expr_result
    

    Further reading available here on stackoverflow:

    • How do chained assignments work? python
    0 讨论(0)
  • 2020-11-29 05:11

    got bitten by python's Chained Assignment today, due to my ignorance. in code

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

    what I expected was

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

    whereas I got below, which produce a self loop in the list, leave me in a endless loop, whoops...

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

    since for a = b = c, one way (python, for example) equivalent to

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

    and have equal right operand for two assignment.

    the other (C++, for example) equivalent to

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

    since in this case a = b = c is basically

    b = c
    a = b
    

    and two right hand operand could be different.

    That why similar code works well in C++.

    0 讨论(0)
  • 2020-11-29 05:12

    @refp's answer is further supported with this output using the dis (disassembly) module:

    >>> 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
    

    The RHS is retrieved and duplicated, then stored into the destination variables left-to-right (try this yourself with e = f = g = h = x).

    Some other posters have been confused if the RHS is a function call, like a = b = fn() - the RHS is only evaluated once, and then the result assigned to each successive variable. This may cause unwanted sharing if the returned value is a mutable, like a list or dict.

    For those using threading, it is useful to note that there is no "atomicity" implied by the chained assignment form over multiple explicit assignment statements - a thread switch could occur between the assignments to g and h, and another thread looking at the two of them could see different values in the two variables.

    From the documentation, 7.2. Assignment statements, g and h being two target lists, x being the expression list:

    assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)
    

    An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

    0 讨论(0)
提交回复
热议问题