Ключевое слово nonlocal. Особенности использования. Примеры
Перед использованием данной темы рекомендуется ознакомиться со следующей темой:
Содержание
- 1. Для чего предназначена инструкция nonlocal? Общая форма использования
- 2. Особенности применения инструкции nonlocal. Отличие между инструкциями global и nonlocal
- 3. Особенности применения инструкции nonlocal в случае, когда используется несколько уровней вложенных функций. Пример
- 4. Требования к объемлющим функциям, которые содержат вложенные функции с инструкциями nonlocal
- 5. Отличия в правилах поиска имен интерпретатором в инструкциях global и nonlocal
- 6. Примеры использования инструкции nonlocal
- 7. Какие ограничения накладываются на инструкцию nonlocal?
- 8. Пример, в котором в инструкции nonlocal объявляется несколько имен
- Связанные темы
Поиск на других ресурсах:
1. Для чего предназначена инструкция nonlocal? Общая форма использования
Инструкция nonlocal используется в случаях, когда в программе реализованы вложенные функции. Инструкция nonlocal предназначена для изменения значения переменной объемлющей функции в теле вложенной функции. Таким образом, вложенная функция имеет доступ к переменным объемлющих функций.
Использование этого механизма дает возможность поддерживать доступную к изменению информацию о состоянии, которое восстанавливается при последующих вызовах вложенной функции.
Общая форма использования инструкции nonlocal
def Fn(): nonlocal name1, name2, ..., nameN
здесь
- Fn() – функция, которая есть вложенной в некоторой другой функции;
- name1, name2, nameN – имена, которые существуют в области видимости объемлющей функции. Функция Fn() есть вложенной в другую объемлющую функцию.
В случае простого вложения функции FnIn() в пределах объемлющей функции FnOut() общая форма объявления инструкции nonlocal следующая:
def FnOut(): ... def FnIn(): nonlocal name1, name2, ..., nameN ...
здесь
- FnOut() – объемлющая функция, в которой объявляется вложенная функция FnIn();
- FnIn() – вложенная функция, которая содержит инструкцию nonlocal;
- name1, name2, nameN – имена, которые объявлены в объемлющей функции FnOut() и используются во вложенной функции FnIn().
⇑
2. Особенности применения инструкции nonlocal. Отличие между инструкциями global и nonlocal
Инструкция nonlocal применяется во вложенных функциях если нужно изменять переменные, которые были объявлены в объемлющих функциях.
Отличие между инструкциями nonlocal и global следующее:
- инструкция global позволяет изменять значения переменных в глобальной области видимости модуля;
- инструкция nonlocal изменяет значение переменных в объемлющей функции. Для глобальной области видимости инструкция nonlocal не имеет действия.
⇑
3. Особенности применения инструкции nonlocal в случае, когда используется несколько уровней вложенных функций. Пример
Пример. Пусть задано несколько вложенных функций. Внешняя функция Fn1() содержит вложенную функцию Fn2(). Вложенная функция Fn2() содержит другую вложенную функцию Fn3(). В функциях Fn1() и Fn2() объявляется переменная с именем x1, которой присваивается некоторое значение. В функции Fn3() переменная x1 изменяется с помощью инструкции nonlocal. В результате будет изменяться переменная x1 ближайшей объемлющей функции, в нашем случае – функции Fn2().
# Инструкция nonlocal # Несколько объемлющих функций def Fn1(): # эта переменная не изменяется из функции Fn3(), # потому что ее перекрывает переменная из функции Fn2() x1 = 25 def Fn2(): x1 = 33 # эта переменная будет изменяться в функции Fn3() def Fn3(): nonlocal x1 x1 = 55 # Fn2.x1 = 55 Fn3() print('Fn2.x1 = ', x1) Fn2() print('Fn1.x1 = ', x1) Fn1()
Результат выполнения программы
Fn2.x1 = 55 Fn1.x1 = 25
Если в теле функции Fn2() убрать строку x1 = 33, то изменяться будет значение переменной x1 функции высшего уровня, то есть функции Fn1(). В этом случае программа выдаст результат
Fn2.x1 = 55 Fn1.x1 = 55
⇑
4. Требования к объемлющим функциям, которые содержат вложенные функции с инструкциями nonlocal
Для того чтобы во вложенной функции использовать инструкцию nonlocal нужно, чтобы выполнялись следующие условия:
- программа содержала код вложенных функций. Одна из функций считается объемлющей, другая – вложенной;
- в объемлющей функции была объявлена переменная, которая изменяется во вложенной функции. Эта переменная должна быть объявлена перед объявлением вложенной функции.
⇑
5. Отличия в правилах поиска имен интерпретатором в инструкциях global и nonlocal
Если во вложенной функции используется инструкция nonlocal, то интерпретатор выполняет следующие действия:
- пропускает локальную область видимости функции, в которой объявлена инструкция nonlocal;
- осуществляет поиск в областях видимости объемлющих функций начиная с ближайшей объемлющей функции.
В случае использования инструкции global во вложенной функции интерпретатор осуществляет поиск в области имен объемлющего модуля (глобальной области видимости).
⇑
6. Примеры использования инструкции nonlocal
Пример 1. В примере продемонстрирован доступ к переменной out объемлющей функции FnOut() из функции FnIn().
# Инструкция nonlocal # Объемлющая функция FnOut() def FnOut(): out = 25 # объявить переменную out # Вложенная функция, в которой используется инструкция nonlocal def FnIn(): # доступ к переменной out объемлющей функции FnOut() nonlocal out out = 777; return # Вызов вложенной функции FnIn() из тела функции FnOut() FnIn() # Вывод переменной out print('FnOut.out = ', out) # Глобальная область видимости. # Вызов функции FnOut() FnOut() # будет выведено: FnOut.out = 777
Результат выполнения программы
FnOut.out = 777
Как видно из результата, переменная out из функции FnOut() была изменена в теле функции FnIn() благодаря инструкции nonlocal.
Пример 2. Решение квадратного уравнения. В примере демонстрируется доступ к переменным x1, x2 объемлющей функции SquareEquition() из вложенной функции Calc().
# Инструкция nonlocal. Решение квадратного уравнения # Подключить математический модуль для того, чтобы # использовать функцию math.sqrt() import math # Объявить две функции: объемлющую SquareEquition() и вложенную Calc() def SquareEquition(a, b, c): # В начале принять, что уравнение не имеет корней x1 = None x2 = None # Вложенная функция Calc() - заполняет значения x1, x2 def Calc(a, b, c): D = b*b-4*a*c if (D>=0): # доступ к x1, x2 объемлющей функции SquareEquition() nonlocal x1, x2 # объявить 2 имени в инструкции nonlocal x1 = (-b - math.sqrt(D))/(2.0*a) x2 = (-b + math.sqrt(D))/(2.0*a) Calc(a, b, c) return [x1, x2] # Использование функции SquareEquition(), # ввод данных print("Input a, b, c:") a = float(input('a = ')) b = float(input('b = ')) c = float(input('c = ')) roots = SquareEquition(a, b, c) print('roots = ', roots)
Результат работы программы
Input a, b, c: a = 1 b = 1 c = -2 roots = [-2.0, 1.0]
⇑
7. Какие ограничения накладываются на инструкцию nonlocal?
На инструкцию nonlocal накладываются следующие ограничения:
- имя, которое объявляется в инструкции nonlocal, на момент вызова во вложенной функции должно уже существовать в объемлющей функции;
- при использовании инструкции поиск имен осуществляется только в областях видимости объемлющих функций. Во встроенной и глобальной областях видимости поиск нелокальных имен не осуществляется, даже если в этих областях такие имена уже существуют (смотрите пример далее).
Пример. Если попробовать выполнить следующий пример
# Ограничения, которые накладываются на nonlocal D = 'Hello' # Объявить глобальное имя def FnOut(): def FnIn(): # Попытка связать имя D с глобальным именем D nonlocal D D = 'world!' # Вызвать функцию FnIn() из тела функции FnOut() FnIn() print('FnIn.D = ', D) # Вызвать функцию FnOut() из области видимости модуля FnOut()
то интерпретатор выдаст ошибку:
SyntaxError: no binding for nonlocal 'D' found
Это означает, что имя D должно быть предварительно объявлено в объемлющей функции FnOut(), а не в глобальной области видимости. Например функция FnOut() может быть изменена следующим образом
... def FnOut(): D = 'Hello' def FnIn(): # имя D связывается с именем D объемлющей функции nonlocal D D = 'world!' # Вызвать функцию FnIn() из тела функции FnOut() FnIn() print('FnIn.D = ', D) ...
После этого программа заработает и выдаст результат
FnIn.D = world!
⇑
8. Пример, в котором в инструкции nonlocal объявляется несколько имен
# Сложение комплексных чисел (a1+b1*j)+(a1+b2*j) def ComplexAdd(a1, b1, a2, b2): a3 = 0 b3 = 0 def Add(): nonlocal a3, b3 # Использование двух имен в инструкции nonlocal a3 = a1+a2 b3 = b1+b2 Add() return [a3, b3] result = ComplexAdd(2, 3, -1, 4) print('result = ', result) # result = [1, 7]
⇑
Связанные темы
- Понятие функции. Общая форма. Примеры объявления и использования функций
- Области видимости имен. Локальные имена. Правила видимости имен. Правило LEGB. Ключевое слово global. Переопределение имен в функциях
- Вложенные функции. Вложенные области видимости. Правила поиска имен в случае вложенных функций. Фабричные функции. Передача значений во вложенную функцию
⇑