Шаг 123.
Основы языка Python.
Пользовательские функции. Вложенные функции

    На этом шаге мы рассмотрим особенности определения и использования вложенных функций.

    Одну функцию можно вложить в другую функцию, причем уровень вложенности не ограничен. При этом вложенная функция получает свою собственную локальную область видимости и имеет доступ к переменным, объявленным внутри функции, в которую она вложена (функции-родителя). Рассмотрим вложение функций на примере.

def func1(x):
    def func2():
        print(x)
    return func2

f1 = func1(10)
f2 = func1(99)
f1() # Выведет: 10
f2() # Выведет: 99
Архив с файлом можно взять здесь.

    Здесь мы определили функцию func1(), принимающую один параметр. Внутри функции func1() определена вложенная функция func2(). Результатом выполнения функции func1() будет ссылка на эту вложенную функцию. Внутри функции func2() мы производим вывод значения переменной х, которая является локальной в функции func1(). Таким образом, помимо локальной, глобальной и встроенной областей видимости, добавляется вложенная область видимости. При этом поиск идентификаторов вначале производится внутри вложенной функции, затем внутри функции-родителя, далее в функциях более высокого уровня и лишь потом в глобальной и встроенных областях видимости. В нашем примере переменная х будет найдена в области видимости функции func1().

    Следует учитывать, что сохраняются лишь ссылки на переменные, а не их значения в момент определения функции. Например, если после определения функции func2() произвести изменение переменной х, то будет использоваться это новое значение:

def func1(x):
    def func2():
        print(x)
    x = 30
    return func2

f1 = func1(10)
f2 = func1(99)
f1() # Выведет: 30
f2() # Выведет: 30
Архив с файлом можно взять здесь.

    Обратите внимание на результат выполнения. В обоих случаях мы получили значение 30. Если необходимо сохранить именно значение переменной при определении вложенной функции, следует передать значение как значение по умолчанию:

def func1(x):
    def func2(x=x): # #  Сохраняем текущее значение, а не ссылку
        print(x)
    x = 30
    return func2

f1 = func1(10)
f2 = func1(99)
f1() # Выведет: 10
f2() # Выведет: 99
Архив с файлом можно взять здесь.

    Теперь попробуем из вложенной функции func2() изменить значение переменной х, объявленной внутри функции func1(). Если внутри функции func2() присвоить значение переменной х, то будет создана новая локальная переменная с таким же именем. Если внутри функции func2() объявить переменную как глобальную и присвоить ей значение, то изменится значение глобальной переменной, а не значение переменной х внутри функции func1(). Таким образом, ни один из изученных ранее способов не позволяет из вложенной функции изменить значение переменной, объявленной внутри функции-родителя. Чтобы решить эту проблему, следует объявить необходимые переменные с помощью ключевого слова nonlocal.

def func1(a):
    x = a
    def func2(b):
        nonlocal x # Объявляем переменную как nonlocal
        print(x)
        x = b # Можем изменить значение х в func1()
    return func2
    
f = func1(10)
f(5)  # Выведет: 10
f(12) # Выведет: 5
f(3)  # Выведет: 12
Архив с файлом можно взять здесь.

    При использовании ключевого слова nonlocal следует помнить, что переменная обязательно должна существовать внутри функции-родителя. В противном случае будет выведено сообщение об ошибке.

    На следующем шаге мы рассмотрим аннотации функций.




Предыдущий шаг Содержание Следующий шаг