Names, namespaces, local vs global variables, function calling. For more, see the execution model.
Memory is divided into cells, and python programs utilize memory by storing data values (numbers, strings, lists, dictionaries, booleans, etc.) in memory cells.
A variable consists of a name and an address in memory at which the value is stored. This is important: a variable does not hold the value directly! A variable is just an address of memory where the actual data value lives.
Note this allows two different variables to label the same data value. Python restricts such sharing to lists and dictionaries.
L = [1, 5, 12]
abc = L
abc.append(22)
print(L)
When python executes the first line, it creates a data value in memory with the contents [1, 5, 12]
and then sets up a variable L
to label this value. Next, abc = L
causes a new variable abc
to be created which labels the same memory address. Thus appending an element to the value labeled by abc
also changes the list L
, so that [1, 5, 12, 22]
is printed.
Only for lists and dictionaries are the data value shared between the variables.
x = 12
y = x
x
and one labeled by y
. The y = x
caused a copy of the data value, instead of sharing the data. This copying is done for numbers, strings, and booleans.Python keeps track of all the variables using a dictionary, called a namespace. A namespace is a dictionary where the keys are strings and the values are memory addresses. Each entry in the namespace is a variable name and address. Python keeps this namespace internally so we do not need to interact with it directly, but we need to be aware of its existence.
When python sees a statement accessing a variable like abc
, it looks up in the namespace dictionary for an entry with key abc
. The associated value is then the address in memory where the value is located.
Assignment statements like x = 12 + 2
first evaluate the expression on the right of the equal sign to a data value, and then create a new entry in the namespace dictionary, with the key equal to x
and the value equal to the address of wherever the data value produced by the expression is located.
Each python source code file has its own namespace. So if you write a python code file like file1.py
with some python code and a file2.py
with some other code, they will have separate namespaces. This means that a variable with name abc
within file1.py
and a variable with name abc
within file2.py
will refer to different data values. When python is executing within file1.py
and sees a variable reference abc
, it looks up in the file1.py
namespace to find the memory address of the data value. Similarly, a variable reference abc
within file2.py
looks in the file2.py
namespace and retrieve a different memory address.
We can access another file's namespace with the import
statement. Each file still looks up names within its own namespace by default, but if the module name is prepended with a dot, python will instead lookup the variable in the namespace for that module. Recall as well that functions are also stored in variables: the function block of code is a data value stored out in memory, and the function name is just a variable with the address of this block of code. Thus these function namespace entries (which are no different than any other entry) are also referenced by the import
statement, allowing us to call functions in a different file.
Python is garbage collected, which means that if some data value (a memory address) is not referenced by any entry in any namespace, the value can no longer be accessed by the python program and therefore is no longer needed. These unreachable values are called garbage and during garbage collection, python will identify these unreachable values and mark that their memory cells can be reused for some other value.
When functions are called, a new namespace is created. This namespace lives until the file returns, at which point the namespace is discarded. Before the start of execution of the body of the function, entries (name, address pairs) for the parameters are added to the namespace.
def somefunction(x):
print(x + 5)
somefunction(12 + 22)
Here, 12 + 22
will be executed to a data value (holding 34) and then a namespace entry of x
and the address of this data value is created. This is so that when print(x + 5)
is executed, python will lookup x
in the namespace and find the address of this value holding 34. At the end of a function, these namespace entries are discarded. So this namespace entry for x
which was created at the start of the function is removed at the end of the function. We call this the scope of x
.
The scope of a variable is the region of the code (think which line numbers) for which the variable is part of the namespace. We would say the variable x
has scope the body of the function somefunction
, meaning that the variable x
is accessible only during the body of the function. Note that when the entry for x
is discarded, the data value holding 34 can no longer be referenced by any entry in a namespace and so is garbage and will be collected (marked as unused) during the next garbage collection.
Variables which are assigned to during the body of a function are called local variables, and are also discarded at the end of the function.
def somefunction(x):
y = x + 4
print(y - 2)
z = 44
somefunction(z - 6)
First, a variable named somefunction
with value the body of the function is added to the file namespace.
Next, a variable named z
with the memory address of a data value holding 44 is added to the file namespace. We call this a global variable since it is added to the namespace of the file outside of any function.
Next, z - 6
is evaluated so a new data value holding 38 is created in memory somehwere.
a new namespace is created as part of the function call.
A variable entry x
with address the address of this value 38 is added to the function namespace as part of the function call.
A variable entry y
with address the address of a value holding 42 is added to the function namespace. Since this is an assignment statement which is part of the body of a function, it is a local variable.
40 is printed
The function body ends, and the function namespace (consisting of entries for x
and y
) is discarded. The values that x
and y
were labeling become garbage.
No homework for today, I will show some examples of the above next time and then have some homework problems.