Namespaces and Scopes in Python

Namespaces and Scopes in Python

Namespace (context) is a naming system thanks to which we can avoid ambiguity when we using the same names. This system in Python looks like dictionaries, where we see mapping from names (keys) to objects (values). The namespaces in Python:

global (in a module)

local (in a function or a method)

built-in (built-in functions/methods and exceptions)

Namespaces have different lifetimes, because they are often created at different points in time. We have only one namespace which is present from beginning to end. The namespaces with built-in names is started when the Python interpreter is started. Global is in a module we are working in. Every function of our program holds its own local namespace. When a function returns or raises an exception, its namespace is deleted.

GLOBAL

————————————————————————

function1      function2      function3      function4

———————————————————————————————————–

BUILT-IN

A scope is the area where a given name can be used with a doubt. The scopes in Python:

scope of functions (contains local names)

scope of a current module (contains global names)

scope of the Python interpreter (contains built-in names)

All variables in Python are local by default. If we want to have global variables, we should declare that. Local variables are better than global ones. We should avoid using global variables.

Our variables defined in a function are always local. We can delete and change them, but it don’t have any effect on other variables outside of the function. The names of these variables can even be the same. The context of them will be different.

If we create a variable in a function, it can be accessed only inside function. The code in the function will read and modify this variable. All variables from the parameter list of the function are local variables too. A global variable created outside a function can be accessed and modified by other functions.

def sumka(a,b):

c = a+b

print(c)

We  have the result:

>>> sumka(23,67)
90
>>> c
Traceback (most recent call last):
  File “<stdin>”, line 1, in <module>
NameError: name ‘c’ is not defined
>>>

The variable named c is a local variable in the function sumka(). When sumka() finished, c will be destroyed, so we will have NameError, when we try to use it outside the function. Objects a and b will be destroyed too after the function’s having finished.

c = 567

def sumka():

c = c +1

We have the result:

>>> sumka()
Traceback (most recent call last):
  File “<stdin>”, line 1, in <module>
  File “<stdin>”, line 2, in sumka
UnboundLocalError: local variable ‘c’ referenced before assignment
>>>

The function can’t find the variable c that is declared outside the function.

c = 567

def sumka():

global c

c = c + 1

We have the result:

>>> sumka()
>>> c
568
>>>

After having declared c as a global variable, the function sumka() can find c outside its local scope.

The global statement can exist in a function anywhere, but the variable the global statement concerns must be placed outside it. We can’t use the global variable either in a for loop or as a parameter in a function definition,  class definition, and an import statement.

A local variable declaration and definition:

var1, var2…

A global variable declaration and definition:

global var1, var2,…

The example with local and global variables:

def korek():

global x

print(x)

x = “Local variable”

print(x)

Let’s run our function:

>>> x =”Which variable?”
>>> korek()
Which variable?
Local variable
>>> print(x)
Local variable
>>> x=”Another string”
>>> korek()
Another string
Local variable
>>> print(x)
Local variable
>>>

The local variable in the function is unchanged (we’re getting the  same string). But the global variable is being changed. In other words, we can have an access to it,

But without assigning to the global variable, we have the result:

>>> korek()
Local variable
Local variable

So our local variable is stronger than the global one. It’s a normal way. But we can assign another string:

>>> x=”Completely other string”
>>> korek()
Completely other string
Local variable

The same! And let’s start again without assigning the string:
>>> korek()
Local variable
Local variable
>>>

Again, our local variable covers the global one.

def korek():

print(x)

x = “A string”

korek()

>>> x=”A string”
>>> korek()
A string
>>>

We assign a string “A string” to variable x, and then call the function. There is no local variable (we don’t assign anything to x inside the function), so the global variable is used.

A variable can’t be both local and global in a function. Every changed or created variable in a function is always local. We can change it into a global one by the use of a global keyword.

def korek():

global x

print(x)

x = “We like local variables”

print(x)

x = “We are assigning a string”

>>> korek()
We are assiging a string
We like local variables
>>> print(x)
We like local variables
>>>

As soon as our function is finished, local variables in the function can’t be accessed from outside.

Let’s look at the local variable in the function:

>>> def korek():
…     x = “local”
…     print(x)

>>> korek()
local
>>> print(x)
Traceback (most recent call last):
  File “<stdin>”, line 1, in <module>
NameError: name ‘x’ is not defined
>>>

Let’s look at the global variable in the function:

>>> def korek():
…     global x
…     x = “global”
…     print(x)
>>> korek()
global
>>> print(x)
global
>>>

In Python 3.x.x, we got a nonlocal keyword. It allows to get an access to the variables declared in parent block of code, but they aren’t accessible for the rest of code like globals  do. In other words, nonlocal variables are accessible in an outer scope, but not in a global one.

The example with a local variable:

def zew1():

a = “outside”

def wew1():

a = “inside”

print(“This is inside: “, a)

wew1()

print(“This is outside: “, a)

Let’s see the result:

>>> zew1()
This is inside:  inside
This is outside:  outside

The example with a nonlocal variable:

def zew2():

a = “outside”

def wew2():

nonlocal a; a = “inside”

print(“This is inside: “, a)

wew2()

print(“This is outside: “, a)

Let’s see the result:

>>> zew2()
This is inside:  inside
This is outside:  inside

I hope you see the difference. The nonlocal variable is something between a local variable and global variable. The nonlocal variable covers an outer variable, so if both an inner (nonlocal) and an outer variable has the same name, inner (nonlocal) wins. This is in the second case. In the first case, however, both variables are local, so each is accessible only in the function it was declared. That’s why, there are no name conflict, and they both are working.

Leave a comment