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

In anticipation of the start of a new stream at the rate “Python Developer”, 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, it comes to scope when familiar with functions. Using their example, we will consider the work of the scope of variables.

Local scope

Consider a function that will list some_list item by element:

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

Here element and some_list – 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 the main body of the program print(element)then we get the error:

NameError: name 'element' is not defined
Теперь мы поступим следующим образом:
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 is the variable element inside a function and a 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 sudden_list is in the global scope, i.e. inside the function print_list we can turn to him, because from the inside you can see what is happening outside. For the reason of such mechanics of work, try to name the local variables inside the function differently from what you call the 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 global, which allows you to change the value of a global variable from within the function. It is written before the name of the variable, which will be deemed global inside the function. As you can see from the example, now the value of the variable candy increases, 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, since this 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 with 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 probability of an error.

Nonlocal scope

This concept appeared in Python 3 along with the keyword nonlocal. The logic of its writing is about the same as that of global. However, nonlocal there is a feature. Nonlocal It is used most often 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. More examples you can find. 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. Variables defined internally are local and externally global.
  2. Outside of functions, no variables defined inside them are visible.
  3. From inside the function, you can change the value of variables that are defined in the global scope using the specifier global.
  4. From the inside nested functions using the nonlocal specifier, you can change the values ​​of variables that were defined in an external function, but are not in the global scope.

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 scope you will make another ours on the way to creating beautiful and readable code.

I also want to invite everyone to free webinar from otus where we’ll study a tool like type annotation in Python: discuss the reasons why many 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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *