Everything you wanted to know about scope in Python, but were embarrassed to ask

In anticipation of the start of a new thread on the course "Python Developer" , we decided to talk about scope in Python. What came of this? - Read the material below.




Today we will talk about important theoretical foundations that must be understood and remembered in order to write competent, readable and beautiful code. We will talk about the scope of variables. This article will be useful not only for beginners, but also for experienced programmers who came to Python from another language and want to understand its mechanics.

Scopes determine in which part of the program we can work with a particular variable, and from which the variable is “hidden”. It is extremely important to understand how to use only those values ​​and variables that we need, and how the language interpreter behaves. We’ll also see how to circumvent the restrictions imposed by scope on actions with variables. In Python, there are as many as 3 scopes:

  • Local
  • Global
  • Nonlocal

The last, nonlocal scope, was added in Python 3.

Usually, we are talking about scope when familiar with functions. Using their example, we will consider the work of the scope of variables.

Local scope


Consider a function that displays a list some_listelement by element:

def print_list(some_list):
    for element in some_list:
        print(element)

Here elementand some_listare local variables that are visible only inside the function, and which cannot be used outside it with the values ​​that were assigned to them inside the function during its operation. That is, if we call in the main body of the program print(element), we get an error:

NameError: name 'element' is not defined


Now we will do the following:

def print_list(some_list):
    for element in some_list:
        print(element) 

element = 'q'
print_list([1, 2, 3])
print(element) 


And we get:

1
2
3
q

Here the variable elementinside the function and the variable with the same name outside it are two different variables, their values ​​do not cross and do not interchange. They are called the same, but refer to different objects in memory. Moreover, a variable named element inside the function lives as long as the function is executed and no more. But be careful in order to give local and global variables the same name, now I will show why:

def print_list(some_list):
    for element in sudden_list:
        print(element) 

sudden_list = [0, 0, 0]
print_list([1, 2, 3])

Result:

0
0
0

Please note that the interpreter did not indicate errors to us. And all because it sudden_listis in the global scope, that is, from the inside of the function print_listwe can access it, because from the inside you can see what is happening outside. For the reason of such mechanics of work, try to name local variables inside the function differently from what you call variables in the global scope.

It is important to talk about constants here. There is no difference to the Python interpreter what you call a variable, so the code above would be better rewritten as follows:

SUDDEN_LIST = [0, 0, 0]

def print_list(some_list):
    for element in SUDDEN_LIST:
        print(element) 

print_list([1, 2, 3]) 

Now everything is in place. The thing is, in Python you cannot somehow strictly define a constant as an object that should not be modified. So the way you use the value of a variable whose name is written in capital letters remains only on your conscience. Another question is that in this way the recorded variable will make it clear to whoever reads your code that the variable will not change anywhere. Or at least it shouldn't.

Global scope


Python has a keyword globalthat allows you to change the value of a global variable from within a function. It is written before the variable name, which will be considered global inside the function. As you can see from the example, now the value of the variable is candyincreasing, and note that we do not pass it as an argument to the function get_candy().

candy = 5

def get_candy():
    global candy 
    candy += 1
    print('  {} .'.format(candy))
    
get_candy()
get_candy()
print(candy)


As a result, we get:


	  6 .
  7 .
7


However, changing the value of a global variable from within the function is not the best practice, and it is better not to do so, because it does not contribute to code readability. The smaller what happens inside the function will depend on the global scope, the better.

Life hack : In order not to suffer from the naming of variables, you can put the main program code into a function main(), then all the variables that will be declared inside this function will remain local and will not spoil the global scope, increasing the likelihood of an error.

Nonlocal scope


This concept appeared in Python 3 along with the keyword nonlocal. The logic of his writing is about the same as that of global. However, nonlocalthere is a feature. NonlocalIt is most often used in nested functions when we want to make the interpreter understand that for a nested function a certain variable is not local, but it is not global in the general sense.

def get_candy():
    candy = 5
    def increment_candy(): 
        nonlocal candy
        candy += 1
        return candy
    return increment_candy
    
result = get_candy()()
print(' {} .'.format(result))

Result:

 6 .

How useful it is for you to decide for yourself. You can find more examples here .

As a conclusion, several rules can be formulated:

  1. From within the function are visible variables that have been defined both inside and outside it. Variables defined internally are local and externally global.
  2. Outside of functions, no variables defined inside them are visible.
  3. , global.
  4. nonlocal , , .

That's all, I hope this material was useful to you, and it shed at least a little light on how the scope works in Python. Having dealt with scopes, you will make another ours on the way to creating beautiful and readable code.

I also want to invite everyone to a free webinar from OTUS, where we will study a tool such as type annotation in Python: discuss the reasons why many people underestimate it, consider a number of examples from military practice when type annotation could save or save the situation. Let's talk about how and when to implement type checking on your projects .

All Articles