Python list doesn’t reflect variable change

Posted on

Question :

Python list doesn’t reflect variable change

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?

Answer #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.

Answered By: Martijn Pieters

Answer #2:

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

palin = ["parrot", polly]
Answered By: girasquid

Answer #3:

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)
Answered By: Mark Reed

Answer #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'
Answered By: Jonatan

Answer #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']]
Answered By: BrenBarn

Answer #6:

The other answers have explained what’s going on well.

This is one of the (several) problems that motivate the use of objects. For example, one might do this:

class Animal:
    def __init__(self, aniType, name):
        self.aniType = aniType
        self.name = name
        self.isAlive = True

    def kill(self):
        self.isAlive = False

    def getName(self):
        return self.name

    def getType(self):
        return self.aniType

    def isLiving(self):
        return self.isAlive


polly = Animal("parrot", "polly")

print(polly.getName()+' the '+polly.getType()+' is alive?')
print(polly.isLiving())

polly.kill()

print(polly.getName()+' the '+polly.getType()+' is alive?')
print(polly.isLiving())

It may look like a lot of code at first for a simple task, but objects are often the way to go for things like this, because they help keep everything organized.

Here’s the output of that program:

polly the parrot is alive?
True
polly the parrot is alive?
False
Answered By: Matthew Adams

Leave a Reply

Your email address will not be published.