Punson
Punson

Reputation: 145

How do you update the values of multiple variables in a loop in Python?

I would like to do something like the following:

x = 1
y = 2
z = 3

l = [x,y,z]

for variable in l:
    variable += 2

print x
print y
print z

Unfortunately, when I print x,y and z after this block, the values have remained at 1,2 and 3 respectively.

I have looked at this related question, but the solution there doesn't solve my problem.

Is there a neat and efficient way to perform the same action to multiple variables like I have tried to above?

P.S. I am using Python 2.6

Upvotes: 11

Views: 5646

Answers (8)

cwallenpoole
cwallenpoole

Reputation: 82048

It's not clear if you want to change the values of X, Y, and Z or the contents of the list. So here are some options:

# as pointed out by the comments this is a bad idea. It violates Pythonic principles
# and your outcomes may be less consistent than you would like
f = locals()
for n in ['x','y','z']:
    f[n] += 2 # modifies the values of the variables

You could also be trying to get a new list which has all updated values. For that use map:

l = map(lambda x: x+2, [x,y,z])
'''
you could also do: 
    l = [x,y,z]
    l = map(lambda x: x+2, l)
'''

Or, you could be trying to update the values of the l list:

l = [x,y,z]
for idx, val in enumerate(l):
    l[idx] = val + 2

Upvotes: 0

jme
jme

Reputation: 20745

I haven't yet seen an answer mention mutability vs. immutability, which is why you're seeing this behavior. It's a really important concept in Python, since it sort of replaces notions of "pass by reference" and "pass by value" that other languages have. See the documentation for an in-depth treatment, but I'll give a quick illustrative example here.

In Python, an int is immutable. That means that the value of an integer cannot be changed. On the other hand, lists and dicts are mutable, meaning they can be changed.

Consider these two cases:

x = (1,2,3,4,5)

for y in x:
    y += 1

print x

This prints:

(1, 2, 3, 4, 5)

Here we tried to update ints, which are immutable. Hence after the for-loop, x remains unchanged. You can sort of think that at each iteration of the loop, the current entry of x is copied to y, and this copy is changed, not the entry itself. Now let's change a mutable type:

x = ([1], [2], [3], [4], [5])

for y in x:
    y += [42]

print x

which prints:

([1, 42], [2, 42], [3, 42], [4, 42], [5, 42])

We see that the elements of x have changed. This is precisely because the elements of x are lists, and lists are mutable.

By the way, you might notice that the container used in both cases was a tuple, which is immutable. You can mutate mutable objects inside of a tuple -- no problem there -- you just can't mutate the tuple itself and the references it contains.

After all of this I still haven't really answered your question, but the answer's sort of implied by the above: you shouldn't store these objects separately, but in a list. Then all of the list comprehension answers given make sense and do what you'd expect.

Upvotes: 1

John La Rooy
John La Rooy

Reputation: 304355

Usually it's better to store the bunch of things you want to manipulate in a list

xyz = [1, 2, 3]

for i in range(len(xyz)):
    xyz[i] += 2

Sometimes (but you should look for other ways first) exec is a good (but be careful if you are exec'ing input under control of a user)

>>> x = 1
>>> y = 2
>>> z = 3
>>> for variable in ['x', 'y', 'z']:
...     exec '{} += 2'.format(variable)
... 
>>> x, y, z
(3, 4, 5)

Upvotes: 1

Marcin
Marcin

Reputation: 238477

You cant change x,y,z like this. x,y,z are integers and they are immutable. You need to make new variables.

x, y, z = (v + 2 for v in l)

Upvotes: 13

Larry Lustig
Larry Lustig

Reputation: 51000

The problem is that variable is scoped to the for loop.

If you were to write

for variable in my_list:
    variable += 2
    print variable

you'd see the values you expect. But, once you get to the next for loop iteration, variable is forgotten and replaced with the next list value.

What you want to do is:

for i in range(len(my_list)):
   list[i] += 2

which will give the effect you want. This is because it's the actual item in the list that's being incremented by 2, not a local copy inside in the for loop.

Upvotes: 2

Avinash Raj
Avinash Raj

Reputation: 174756

You could try something like below using list comprehension and then assign the values returned to the variables x, y, z

>>> x = 1
>>> y = 2
>>> z = 3
>>> lst = [x,y,z]
>>> [i+2 for i in lst]
[3, 4, 5]
>>> x, y, z = [i+2 for i in lst]
>>> x
3
>>> y
4
>>> z
5

As said in the below comment , don't use list as a variable name. list is a special function used for creating a list.

Upvotes: 1

venpa
venpa

Reputation: 4318

You could use list comprehension:

 print [variable+2 for variable in list]

'variable' in your case is local variable and it's scope is diminished once you exit the for loop. It's better to avoid the list name as list as it's in-built

Upvotes: 1

Martin Konecny
Martin Konecny

Reputation: 59651

look into map.

x = 1
y = 2
z = 3

l = [x,y,z]

l = map(lambda x: x+2, l)  # [3, 4, 5]

You are essentially "mapping" one list to another, with the modification for each element defined by your lambda function.

Upvotes: 1

Related Questions