Python list doesn't reflect variable change

19,398

Solution 1

Python variables hold references to values. Thus, when you define the palin list, you pass in the value referenced by polly, not the variable itself.

You should imagine values as balloons, with variables being threads tied to those balloons. "alive" is a balloon, polly is just a thread to that balloon, and the palin list has a different thread tied to that same balloon. In python, a list is simply a series of threads, all numbered starting at 0.

What you do next is tie the polly string to a new balloon "dead", but the list is still holding on to the old thread tied to the "alive" balloon.

You can replace that thread to "alive" held by the list by reassigning the list by index to refer to each thread; in your example that's thread 1:

>>> palin[1] = polly
>>> palin
['parrot', 'dead']

Here I simply tied the palin[1] thread to the same thing polly is tied to, whatever that might be.

Note that any collection in python, such as dict, set, tuple, etc. are simply collections of threads too. Some of these can have their threads swapped out for different threads, such as lists and dicts, and that's what makes something in python "mutable".

Strings on the other hand, are not mutable. Once you define a string like "dead" or "alive", it's one balloon. You can tie it down with a thread (a variable, a list, or whatever), but you cannot replace letters inside of it. You can only tie that thread to a completely new string.

Most things in python can act like balloons. Integers, strings, lists, functions, instances, classes, all can be tied down to a variable, or tied into a container.

You may want to read Ned Batchelder's treatise on Python names too.

Solution 2

When you put a string in a list, the list holds a copy of the string. It doesn't matter whether the string was originally a variable, a literal value, the result of a function call, or something else; by the time the list sees it, it's just a string value. Changing whatever generated the string later will never affect the list.

If you want to store a reference to a value that will notice when that value changes, the usual mechanism is to use a list containing the "referenced" value. Applying that to your example, you wind up with a nested list. Example:

polly = ["alive"]
palin = ["parrot", polly]
print(palin)
polly[0] = "dead"
print(palin)

Solution 3

Before your second print statement, store your new values into palin:

palin = ["parrot", polly]

Solution 4

The list will contain values only, not references to variables as you would like. You could however store a lambda in the list, and have the lambda look up the value of your variable.

>>> a = 'a'
>>> list = ['a',lambda: a]
>>> list[1]
<function <lambda> at 0x7feff71dc500>
>>> list[1]()
'a'
>>> a = 'b'
>>> list[1]()
'b'

Solution 5

You can't. Assignment to a bare name is Python always only rebinds the name, and you cannot customize or monitor this operation.

What you can do is make polly a mutable object instead of a string, and mutate its value instead of rebinding the name. A simple example:

>>> polly = ['alive']
>>> items = ['parrot', polly]
>>> items
['parrot', ['alive']]
>>> polly[0] = 'dead'
>>> items
['parrot', ['dead']]
Share:
19,398

Related videos on Youtube

Flexo1515
Author by

Flexo1515

Updated on September 15, 2022

Comments

  • Flexo1515
    Flexo1515 over 1 year

    When I write this code:

    polly = "alive"
    palin = ["parrot", polly]
    print(palin)
    polly = "dead"
    print(palin)
    

    I thought it would output this:

    "['parrot', 'alive']"
    "['parrot', 'dead']"
    

    However, it doesn't. How do I get it to output that?

  • Flexo1515
    Flexo1515 over 11 years
    Anyway to do it without restoring the new value?
  • David Robinson
    David Robinson over 11 years
    @user1404053: Not the way you're asking. In Python strings are immutable, so there's no way to change the value in polly and therefore change it everywhere else. The line polly = "dead" is a rebinding operation rather than a mutating one
  • Flexo1515
    Flexo1515 over 11 years
    Thank you, I believe now that I asked the incorrect question but thank you
  • mgilson
    mgilson over 11 years
    I like the balloon analogy -- especially if they're helium balloons which float away when the last string is released... (+1).
  • Matthew Adams
    Matthew Adams over 11 years
    Some more explanation: here lambda: a is basically a function that just returns the value stored in a. That's why you can use the command list[1](); it means you call the function stored in list[1]. (Also, appropriate gravatar, @Jonatan)
  • Martijn Pieters
    Martijn Pieters over 11 years
    @user1404053: I updated some more to explain how strings are not mutable. You have to replace one string "balloon" with another.
  • DSM
    DSM over 11 years
    Does this mean garbage collection strategies correspond to weather?
  • Martijn Pieters
    Martijn Pieters over 11 years
    @DSM: Exactly :-) GC is the wind that blows away any balloons not tied down. :-)
  • mgilson
    mgilson over 11 years
    @DSM -- I was more thinking that garbage collection strategies correspond to parties (or maybe just small children at the fair ...). However, meteorology always seemed like a party of an occupation to get into, so ... Tomato, tomato.
  • Jonatan
    Jonatan over 11 years
    Quite right, thanks for the explanation. Also I had completely forgotten my avatar, haha!
  • Flexo1515
    Flexo1515 over 11 years
    Was more wondering how to change one variable so that multiple lists would reflect the change without needing to be changed individually
  • Martijn Pieters
    Martijn Pieters over 11 years
    @user1404053: then you need a mutable balloon. A user-defined class, for example, instead of a string.
  • mgilson
    mgilson over 11 years
    @user1404053 mutable balloons ... I suppose those would be the long skinny ones that clowns can turn into other things (like dogs or hats). All joking aside, this is a problem that the Tkinter people ran into when designing the python-tk interface. They created helper classes StringVar and IntVar for this sort of purpose. They're very simple classes which have some data attribute and then you can just swap out what "balloon" that attribute is "tied" to.
  • Flexo1515
    Flexo1515 over 11 years
    I replaced the strings with int ("alive" became 3 and "dead" became 4) and still no change, even when using palin[1] = polly
  • TimothyAWiseman
    TimothyAWiseman over 11 years
    This is a great explanation. I would add that you could do something similar to what @user1404053 is asking using a user-defined class and you could have great control over how it was implemented by using properties ( docs.python.org/library/functions.html#property ).
  • dreftymac
    dreftymac almost 7 years
    Nice analogy for explaining valueType versus referenceType