backlinks to this page:
Variables have a certain scope, where they can exist. This can be at top-level, inside a function or inside a class. A Variable inside a class instance (usually prefix with
self. ) is called an attribute.
A python function can access (read) a variable when this variable was declared at top-level. It is important to know that each function in python has it's own scope for variables. All variables declared inside a function are local and can not be seen by any other function, nor by code at top-level. Meaning you can have a variable at top-level, and you can declare inside a function a a local variable with the same name. Both variables are separated by python.
Interesting is the fact that you can not only read, but also manipulate (changing the value of) a top-level variables inside a function…and the manipulation will be visible at top-level! This only works with mutable types, like
list (square brackets). A
tuple (round bracket) on the other hand is immutable.
Important is not to confuse those two things:
x = 4
cells = "x"
In short, as soon as you declare a variable inside a function, you create a new local variable. Independent of the fact that a variable with the same name exist at top-level. You best try out this interactive python shell session below. Several functions will be declared and used, to check if they could manipulate variables from top-level.
cells = [1,2,3,4] # top-level >>> def adder(): """adding 5 to cells""" cells.append(5) >>> print(cells) [1, 2, 3, 4] >>> adder() >>> print(cells) [1, 2, 3, 4, 5]As can be seen in the example above, the function
adder()was able to manipulate the top-level variable
cells. Because cells is a list and lists are mutable.
>>> def local_adder(): cells = [1,2,3] cells.append(77) >>> local_adder() >>> print(cells) [1, 2, 3, 4, 5]Contrary, in the example above nothing new was added to
cellsby the function
local_adder()declared a local variable inside a function. At this moment, a local
cellsexisted and the top-level
cells. Only the local
cellsgot the 77 added, but the function itself had no
print()to show this. After the function call, the top-level
cellshad excatly the same values as before.
>>> coordinates = (44,55) >>> print(coordinates) (44, 55) >>> def invert_coordinates(): coordinates = (-coordinates, -coordinates) >>> invert_coordinates() Traceback (most recent call last): File "<pyshell#25>", line 1, in <module> invert_coordinates() File "<pyshell#22>", line 2, in invert_coordinates coordinates = (-coordinates, -coordinates) UnboundLocalError: local variable 'coordinates' referenced before assignmentManipulating an immutable tuple is not possible, but in the example above the problem is not the type of
coordinatesbut the scope: Inside the
invert_coordinates()function, a new local variable
coordinatesis declared. The the function tries to assign it the (inverted) value of the top-level variable with the same name. And this same name is the problem: python can not access the top-level variable
coordinateanymore because the name is overwritten by the local variable
>>> def invert_coordinates(): coordinates = (-1,-2) >>> coordinates (44, 55) >>> invert_coordinates() >>> coordinates (44, 55)The example above shows that a local variable (with same name as existing top-level variable) can be created inside a function without manipulating the top-level variable at all. This all with an immutable tuple.
>>> def creator(): secret="i am local only" print("inside function:", secret) >>> secret Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> secret NameError: name 'secret' is not defined >>> creator() inside function: i am local only >>> secret Traceback (most recent call last): File "<pyshell#37>", line 1, in <module> secret NameError: name 'secret' is not definedThe example above shows the same fact from another perspective: the local variable
secretis well visible….but inside it's function only. not at top-level.
>>> cells [1, 2, 3, 4, 66] >>> def creator2(): cells = [-1,-2,-3] print("local cells:", cells) >>> creator2() local cells: [-1, -2, -3] >>> cells [1, 2, 3, 4, 66]Again, a local variable can be declared inside a function, without conflicts with top-level variable of the same time. This time the variables are of the mutable type list.
>>> def creator3(): cells = [cells[-1], cells] print("local cells:", cells) >>> cells [1, 2, 3, 4, 66] >>> creator3() Traceback (most recent call last): File "<pyshell#51>", line 1, in <module> creator3() File "<pyshell#49>", line 2, in creator3 cells = [cells[-1], cells] UnboundLocalError: local variable 'cells' referenced before assignment
In the example above, again the problem of overwriting
cells inside the function with a local variable
cells and then trying to access the top-level
cells: Not possible, because the name
cells inside the function is already overwritten. It would work by choosing another name for the local variable.
>>> coordinates (44, 55) >>> def swapper(original): return (original[-1],original) >>> coordinates (44, 55) >>> new_c = swapper(coordinates) >>> new_c (55, 44) >>> def doubler(): return (coordinates*2, coordinates*2) >>> coordinates (44, 55) >>> c2 = doubler() >>> c2 (88, 110)
And finally how it should be done: If a function want to manipulate an immutable top-level variable, it should use the
return statement and the function caller should assign the returned value to a variable.