bhsantos
bhsantos

Reputation: 3

How does a comma followed by a variable assignment concatenate?

I am still in the early stages of learning Python and came accross this syntax but I have no idea what it does.

check, expression = expression, expression.replace('()', '').replace('[]', '').replace('{}', '')

Now I know what the str.replace() function does, I am just unclear in how in the end is "check" being assigned to this concatenation of replace functions.

Context:

Here is the full code for context, the purpose of it is just to check wether brackets are being used correctly in a given string:

BRACKETS = ("{","[","(","}","]",")")
list = []

#Creating a list with only the brackets in it.
for c in expression:
    if (c in BRACKETS) and (c in expression):
        list.append(c)

expression = ''.join(list)

while expression:
    check, expression = expression, expression.replace('()', '').replace('[]', '').replace('{}', '')
    if expression == check:
        return False
return True

Upvotes: 0

Views: 88

Answers (3)

Jared Goguen
Jared Goguen

Reputation: 9010

Consider the following example:

a = 'a'
b = 'b'

temp = a
a = b
b = temp

print(a) # 'b'
print(b) # 'a'

From this, it can be seen that the three lines in the middle swap the values of a and b. In Python, tuple packing and unpacking can be used in order to eliminate the need for the temporary variable.

a = 'a'
b = 'b'

temp_tuple = b, a # tuple packing
print(temp_tuple) # ('b', 'a')

a, b = temp_tuple # tuple unpacking
print(a) # 'b'
print(b) # 'a'

Now, we can combine this packing and unpacking into a single expression.

a = 'a'
b = 'b'

a, b = b, a

print(a) # 'b'
print(b) # 'a'

You code saves the original value of expression into check and saves the updated version of expression back into expression. It then compares the two variables to see whether expression was changed by all the replace calls.

Edit: Regarding the comment about whether Python goes through the code segment three times, we can use to dis module to disassemble the Python bytecode for a test function.

from dis import dis

def test(expression):
    while expression:
        check, expression = expression, expression.replace('()', '').replace('[]', '').replace('{}', '')
        if expression == check:
            return False
    return True

print dis(test)

This prints the following (with some annotations):

# while expression:
4           0 SETUP_LOOP              75 (to 78)
      >>    3 LOAD_FAST                0 (expression)   # start
            6 POP_JUMP_IF_FALSE       77                # jump to exit

# check, expression = [...]
5           9 LOAD_FAST                0 (expression)
           12 LOAD_FAST                0 (expression)
           15 LOAD_ATTR                0 (replace)
           18 LOAD_CONST               1 ('()')
           21 LOAD_CONST               2 ('')
           24 CALL_FUNCTION            2
           27 LOAD_ATTR                0 (replace)
           30 LOAD_CONST               3 ('[]')
           33 LOAD_CONST               2 ('')
           36 CALL_FUNCTION            2
           39 LOAD_ATTR                0 (replace)
           42 LOAD_CONST               4 ('{}')
           45 LOAD_CONST               2 ('')
           48 CALL_FUNCTION            2
           51 ROT_TWO             
           52 STORE_FAST               1 (check)
           55 STORE_FAST               0 (expression)

# if check == expression:
6          58 LOAD_FAST                0 (expression)
           61 LOAD_FAST                1 (check)
           64 COMPARE_OP               2 (==)
           67 POP_JUMP_IF_FALSE        3                # jump to start

# return False
7          70 LOAD_GLOBAL              1 (False)
           73 RETURN_VALUE        
           74 JUMP_ABSOLUTE            3                # jump to start
      >>   77 POP_BLOCK                                 # exit

# return True
8     >>   78 LOAD_GLOBAL              2 (True)
           81 RETURN_VALUE        

From this it can be seen that the following occurs:

  1. expression is loaded and checked for its truthiness. If True, the loop immediately exits.
  2. The values of check and expression are loaded, updated, swapped, and stored.
  3. The value of check is compared to that of expression. If False, the loop jumps to the start. Otherwise, False is returned.
  4. The value of True is returned. This will only occur if the loop exited because the value of expression was not truthy in the first step.

I think that the only real thing to note in the check, expression = [...] line is the use of the instruction ROT_TWO, which swaps the two top-most stack items. On line 9, the value of expression is loaded. On lines 12-48, the value of expression loaded and updated, pushing the value loaded on line 9 back in the stack. Then, on line 51, these two values are swapped.

Upvotes: 1

kindall
kindall

Reputation: 184161

The line you're asking about is equivalent to:

check      = expression
expression = expression.replace('()', '').replace('[]', '').replace('{}', '')

Python allows multiple assignments with a single =. Each variable on the left side is assigned a corresponding value from the right side.

Upvotes: 1

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48067

Explanation

For example:

x, y = 1, 2

x will be initialized with 1 & y be initialized with 2.

You can also use this to unwrap tuples. For e.g

>>> def foo(): return 1, 2
>>> x = foo()
>>> x  # It is tuple
(1, 2)   
>>> x, y = foo()  # Value of 'x' is 1 and 'y' is 2
>>> x
1
>>> y
2

You can also use this to swap two numbers as a, b = b, a

Upvotes: 0

Related Questions