# How or when is a variable updated?

## Question:

I wrote this code (spoilers for LeetCode problem 13):

``````roman_numbers = [('I', 1), ('V', 5), ('X', 10), ('L', 50), ('C', 100), ('D', 500), ('M', 1000)]

class Solution:
def get_value(self, number):
return dict(roman_numbers)[str(number)]

def romanToInt(self, s: str) -> int:
result = 0
letter_list = list(letter for letter in s)
for letter in s:
try:
if self.get_value(letter_list[0]) >= self.get_value(letter_list[1]):
result += self.get_value(letter_list[0])
letter_list.remove(letter_list[0])
else:
result -= self.get_value(letter_list[0])
letter_list.remove(letter_list[0])
except IndexError:
result += self.get_value(letter_list[0])
return result
``````

The code works, but I wanted to refactor it to make it less repetitive. The pattern `self.get_value(letter_list[x])` appears many times, so I’d like to make a variable that stores a result like `letter_list.remove(letter_list[0])`, so I can write code like

``````if letter0 >= letter1:
result += letter0
``````

But since the `letter_list` will change, I need to make sure that the variables are updated when necessary.

I tried creating the variable inside the `for` loop, so that it updates every time through the loop:

``````for letter in s:
letter0 = self.get_value(letter_list[0])
letter1 = self.get_value(letter_list[1])
...
``````

However, I’m not sure that I’ve properly understood what’s going on.

What exactly causes the variables to update? Is it because the code is inside a function? Is the variable getting re-created each time through the loop?

And is this correct logic – will the variables be up-to-date when they are used? In the past I’ve had many problems with variable values getting out of sync.

## Answers:

What makes the variable change is the assignment operation:

``````letter0 = ...
``````

Whatever is to the right of the assignment (=, += etc) is evaluated/executed first, then the result is stuffed in the variable. But no, in Python variables do not evaporate when you reach the bottom of the loop (scope) they are defined in. The next assignment simply replaces what the variable referred to before.

So, variables are just names that refer to objects. You seem to expect a variable to hold an expression that will be dynamically executed. That’s not how that works. Variables hold the result of expressions. If you use the following assignment statement:

``````letter0 = self.get_value(letter_list[0])
``````

Then `letter0` is now referring to the object that results from evaluating the expression `self.get_value(letter_list[0])`. In this case, it is some `str` object. When you use the variable in code after that, it simply evaluates to that string object. It doesn’t re-evaluate the expression that was used in the assignment statement: `self.get_value(letter_list[0])`.

There are two ways you might "update" a variable.

1. assign or re-assign to it.
2. you mutate the object that the variable is referring to.

Those are two different things though. Really, only (1) is updating the variable. The other is mutating some object.

Now, you should really read through the whole of Ned Batchelder’s excellent Facts and Myths about Python Names and Values (he’s a StackOverflow legend). But I want to highlight one point made there: lot’s of different things are assignments, not just the simple assignment

``````<some-var> = <some-expression>
``````

e.g.

``````result = some_function()
``````

Here are the various ways you can assign to the name `X`:

``````X = ...
for X in ...
[... for X in ...]
(... for X in ...)
{... for X in ...}
class X(...):
def X(...):
def fn(X): ... ; fn(12)
with ... as X:
except ... as X:
import X
from ... import X
import ... as X
from ... import ... as X
``````

As for mutating an object, that is generally done through some mutator method, e.g.:

``````my_object.mutator_method(some_arg)
``````

For example, here are two different mutator methods being called on the same object through the variable `mylist`:

``````mylist.append(42)
mylist.pop()
``````

Note, operators and various other language constructs can also mutate an object because underneath the hood, the end up calling a mutator method!

``````mylist += [42]  # This one actually is an assignment too!
mylist[i] = 42  # This one is *not an assignment*!
``````

Watch out with that last one! It’s actually not an assignment!

Categories: questions
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.