Использование глобальных переменных в функциях
Иногда возникает необходимость в использовании глобальных переменных в функциях. Глобальная переменная — это такая переменная, которая определена вне функции и может быть использована в любой части программы, включая функции.
Типичная проблема
Возьмем пример программы, которая использует функцию для изменения глобальной переменной.
x = 10 def change_x(): x = 5 change_x() print(x)
В данном случае ожидается, что переменная x изменит свое значение на 5 после вызова функции change_x() . Однако, когда программа выводит значение x с помощью print(x) , оно все еще равно 10 . Почему так происходит?
Пояснение
Проблема возникает из-за области видимости переменных в Python. Когда в функции создается переменная с тем же именем, что и глобальная переменная, Python предполагает, что это новая локальная переменная, которая существует только внутри функции.
Решение
Для того чтобы изменить глобальную переменную внутри функции, необходимо использовать ключевое слово global перед именем переменной.
x = 10 def change_x(): global x x = 5 change_x() print(x)
Теперь, когда функция change_x() вызывается, она изменяет глобальную переменную x на 5 , и print(x) выводит 5 .
Использование глобальной переменной в других функциях
Глобальные переменные также можно использовать в других функциях. Например:
x = 10 def print_x(): print(x) print_x()
В этом случае функция print_x() выводит значение глобальной переменной x , которое равно 10 .
Но стоит помнить, что чрезмерное использование глобальных переменных может усложнить отладку и поддержку программы, поскольку они могут быть изменены в любом месте программы.
Как указать глобальную переменную в python
Область видимости или scope определяет контекст переменной, в рамках которого ее можно использовать. В Python есть два типа контекста: глобальный и локальный.
Глобальный контекст
Глобальный контекст подразумевает, что переменная является глобальной, она определена вне любой из функций и доступна любой функции в программе. Например:
name = "Tom" def say_hi(): print("Hello", name) def say_bye(): print("Good bye", name) say_hi() say_bye()
Здесь переменная name является глобальной и имеет глобальную область видимости. И обе определенные здесь функции могут свободно ее использовать.
Локальный контекст
В отличие от глобальных переменных локальная переменная определяется внутри функции и доступна только из этой функции, то есть имеет локальную область видимости:
def say_hi(): name = "Sam" surname = "Johnson" print("Hello", name, surname) def say_bye(): name = "Tom" print("Good bye", name) say_hi() say_bye()
В данном случае в каждой из двух функций определяется локальная переменная name. И хотя эти переменные называются одинаково, но тем не менее это две разных переменных, каждая из которых доступна только в рамках своей функции. Также в функции say_hi() определена переменная surname, которая также является локальной, поэтому в функции say_bye() мы ее использовать не сможем.
Скрытие переменных
Есть еще один вариант определения переменной, когда локальная переменная скрывают глобальную с тем же именем:
name = "Tom" def say_hi(): name = "Bob" # скрываем значение глобальной переменной print("Hello", name) def say_bye(): print("Good bye", name) say_hi() # Hello Bob say_bye() # Good bye Tom
Здесь определена глобальная переменная name. Однако в функции say_hi определена локальная переменная с тем же именем name. И если функция say_bye использует глобальную переменную, то функция say_hi использует локальную переменную, которая скрывает глобальную.
Если же мы хотим изменить в локальной функции глобальную переменную, а не определить локальную, то необходимо использовать ключевое слово global :
name = "Tom" def say_hi(): global name name = "Bob" # изменяем значение глобальной переменной print("Hello", name) def say_bye(): print("Good bye", name) say_hi() # Hello Bob say_bye() # Good bye Bob
nonlocal
Выражение nonlocal прикрепляет идентификатор к переменной из ближайщего окружающего контекста (за исключением глобального контекста). Обычно nonlocal применяется во вложенных функциях, когда надо прикрепить идентификатор за переменной или параметром окружающей внешней функции. Рассмотрим ситуацию, где это выражение может пригодиться:
def outer(): # внешняя функция n = 5 def inner(): # вложенная функция print(n) inner() # 5 print(n) outer() # 5
Здесь вложенная локальная функция inner() выводит на консоль значение переменной n , которая определена во внешней функции outer(). Затем в функции outer() вызывается внутренняя функция inner().
При вызове функции outer() здесь мы ожидаемо увидим на консоли два раза число 5. Однако в данном случае вложенная функция inner() просто получает значение. Теперь возьмем другую ситуацию, когда вложенная функция присваивает значение переменной:
def outer(): # внешняя функция n = 5 def inner(): # вложенная функция n = 25 print(n) inner() # 25 print(n) outer() # 5 # 25 - inner # 5 - outer
При присвоении значения во вложенной функции: n = 25 будет создаваться новая переменная n, которая скроет переменную n из окружающей внешней функции outer. В итоге мы получим при выводе два разных числа. Чтобы во вложенной функции указать, что идентификатор во вложенной функции будет представлять переменную из окружающей функции, применяется выражение nonlocal :
def outer(): # внешняя функция n = 5 def inner(): # вложенная функция nonlocal n # указываем, что n - это переменная из окружающей функции n = 25 print(n) inner() # 25 print(n) outer() # 25
Задать глобальную переменную Python
называют переменную, к которой можно получить доступ из всех блоков кода, однако задать ее возможно только в общем пространстве кода. Если мы задаем переменную внутри блока (функции или цикла), то она уже будет доступна только в их пределах, в соответствии с чем она называется . Смотрите пример:
var1 = 3 def my_func(): var2 = 2 print(f’var1 inside function:’, var1) print(f’var2 inside function:’, var2) my_func() print(f’var1 outside function:’, var1) print(f’var2 outside function:’, var2)
Результат выполнения кода:
var1 inside function: 3 var2 inside function: 2 var1 outside function: 3 NameError: name ‘var2’ is not defined. Did you mean: ‘var1’?
Инструкции global и nonlocal в Python, как использовать
Ссылки для тех кто ищет встроенные функции globals() и locals() .
Инструкция global :
Инструкция global это объявление, которое выполняется для всего текущего блока кода. Это означает, что перечисленные в инструкции переменные должны интерпретироваться как глобальные. Свободные переменные могут ссылаться на глобальные переменные с помощью global , не будучи объявленными в глобальной области.
Имена, перечисленные в инструкции global , не должны использоваться в блоке кода, текстуально предшествующем global .
Имена, перечисленные в инструкции global , не должны быть определены как аргументы функции или использоваться в целевом элементе item управления циклом for item in . . Не должны быть связаны с именем в определении класса, определении функции, оператора import или аннотации переменной.
Инструкция global , переданная в строке или объекте кода в функцию exec() , не влияет на блок кода, содержащий вызов функции, и на код, содержащийся в такой строке. То же самое относится к функциям eval() и compile() .
Посмотреть все глобальные переменные можно при помощи вызова встроенной функции globals() из любой области видимости.
Инструкция nonlocal :
Инструкция nonlocal вызывает перечисленные имена для обозначения ранее определенных переменных в ближайшей области видимости, исключая глобальную. Это важно потому, что интерпретатор сначала выполняет поиск в локальном пространстве имен. Оператор позволяет инкапсулированному коду связывать переменные вне локальной области, кроме глобальной (модульной) области.
Имена, перечисленные в инструкции nonlocal , в отличие от тех, что перечислены в инструкции global , должны ссылаться на ранее существовавшие переменные в охватывающей области.
Имена, перечисленные в выражении nonlocal , не должны вступать в противоречие с ранее существующими переменными, определенными локальной области видимости.
Посмотреть все локальные переменные определенной области видимости можно при помощи вызова встроенной функции locals() из этой области видимости.
Обобщая сказанное:
- операторы global и nonlocal используются в области видимости той функции, где будет требуется изменение переменной;
- оператор global можно использовать как в простых функциях, так и во вложенных;
- оператор nonlocal используются во вложенных функциях с переменными, которые уже существуют в ближайшей области видимости;
- с помощью оператора global можно определить глобальную переменную из области видимости функции, которая ранее отсутствовала;
- при использовании оператора nonlocal , переменные родительской функции должны существовать.
Важно:
Никогда не используйте инструкцию global , если глобальная переменная только используется в теле функции. Применяйте эту инструкцию, когда функция изменяет связывание глобальной переменной. Хороший стиль программирования предполагает использование инструкции global исключительно в случае, когда это остро необходимо, так как ее наличие в коде заставляет предполагать, что она включена в программу для каких то полезных целей. Если, все таки, без нее невозможно обойтись, то пишите оператор global в блоке функции в качестве первой инструкции.
Примеры использования global и nonlocal
Изменение глобальной переменной внутри функции с помощью global .
def plus(): print('В коде определены глобальные переменные:\n', key: val for key, val in globals().items() if 'global' in key>) # Локальная область видимости функции plus() # Здесь глобальные переменные ДОСТУПНЫ ТОЛЬКО ДЛЯ ЧТЕНИЯ print('=> Попытка изменить глобальную переменную `global_a`') try: global_a = global_a + 1 except UnboundLocalError: print('. Ошибка: UnboundLocalError (Локальное имя указано, но не привязано к значению)\n' 'Эта ошибка говорит о том, что глобальную переменную `global_a` ' 'НЕЛЬЗЯ ИЗМЕНИТЬ внутри функции plus()') finally: global_a = 1 # Здесь создалась новая локальная переменная функции plus(), # которая хранит свое значение только внутри функции plus() # и не имеет ни чего общего с глобальной переменной `global_a`. # В Python это называется скрытием глобальной переменной print('global_a =', global_a, '=> создана новая локальная переменная ' 'функции plus()') # Укажем, что `global_b` - глобальная, для функции plus() global global_b print('Доступные переменные в функции `plus()`:', locals()) # Изменим глобальную переменную `global_b` на 100 global_b = global_b + 50 # Глобальная область видимости # Определим глобальные переменные global_a = 10 global_b = 100 # вызываем функцию plus() print(global_a, '=> Глобальная переменная `global_a` НЕ изменилась.') print(global_b, '=> Глобальная переменная `global_b` изменена ' 'внутри функции plus()')
Создание глобальной переменной из локальной области видимости функции.
def plus(): # Локальная область видимости функции `plus()` print('Словарь глобальных переменных в начале определения функции `plus()`:\n', key: val for key, val in globals().items() if 'global' in key>) # `global_a` еще ни где не определена global global_a # Глобальные переменные могут отсутствовать при их создании global_a = 50 # Создаст переменную `global_a` в глобальной области видимости global_a = global_a - 10 def nested(): """Вложенная функция `nested()`""" # локальная область видимости вложенной функции nested() # Что бы изменить глобальную переменную `global_a`, мы # должны указать с помощью оператора global, что эта # переменная для вложенной функции то же является глобальной global global_a global_a = global_a - 10 # С помощью оператора `global` можно создавать # глобальные переменные, так же во вложенных функциях global global_b global_b = 0 # Создаст переменную `global_b` в глобальной области видимости global_b = global_b + 5 # Выполним вложенную функцию nested() # Изменим глобальную переменную `global_b`, созданную # во вложенной функции, для этого укажем с помощью # оператора `global`, что эта переменная для родительской # функции то же является глобальной global global_b global_b = global_b + 5 print('Словарь глобальных переменных в конце определения функции `plus()`:\n', key: val for key, val in globals().items() if 'global' in key>) # Глобальная область видимости. Какие либо переменные отсутствуют. # вызов функции plus() plus() global_a = global_a + 100 print(global_a, '=> глобальная переменная global_a, созданная ' 'в функции plus() изменена в глобальной области видимости') global_b = global_b + 50 print(global_b, '=> глобальная переменная global_b, созданная ' 'во вложенной функции nested() изменена в глобальной области видимости')
Изменение переменных в соседних областях видимости с помощью nonlocal .
def plus(): # Локальная область видимости функции `plus()` # Определим локальные переменные функции `plus()` plus_a = 5 plus_b = 10 print('Локальные переменные функции `plus()`:', locals()) def nested(): """Вложенная функция `nested()`""" # локальная область видимости вложенной функции `nested()` # Здесь локальные переменные функции `plus()` ДОСТУПНЫ ТОЛЬКО ДЛЯ ЧТЕНИЯ print('=> Попытка изменить локальную переменную функции `plus()`') try: plus_a = plus_a + 1 except UnboundLocalError: print('. Ошибка: UnboundLocalError (Локальное имя указано, но не привязано к значению)\n' 'Эта ошибка говорит о том, что локальную переменную `plus_a`, созданную во внешней ' 'функции `plus()` НЕЛЬЗЯ ИЗМЕНИТЬ внутри вложенной функции nested()') finally: plus_a = 1 # Здесь создалась новая локальная переменная функции `nested()`, # которая хранит свое значение только внутри функции `nested()` # и не имеет ни чего общего с локальной переменной plus_a, которая # определялась ранее в локальной области видимости функции `plus()` print('plus_a =', plus_a, '=> создана новая локальная переменная ' 'в области видимости функции `nested()`') # Укажем, что plus_b - не локальная, для вложенной функции `nested()` # . Нелокальные переменные должны существовать, т.е. должны быть # определены в ближайшей (вышестоящей) области видимости)! nonlocal plus_b print('Доступные переменные в функции `nested()`', locals()) plus_b = plus_b + 10 print(plus_b, '=> Переменная plus_b, локальной области функции plus(), ' 'изменена внутри области видимости вложенной функции `nested()`') # вызов вложенной функции `nested()` внутри функции `plus()` nested() print(plus_a, '=> Локальная переменная plus_a, созданная в функции ' '`plus()` НЕ изменилась.') print(plus_b, '=> Локальная переменная plus_b, созданная в функции ' '`plus()` изменена внутри вложенной функции nested()') ###################### # вызов функции plus() plus()
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Функции это объекты
- Функции могут иметь атрибуты
- Функции могут храниться в структурах данных
- Функции могут быть вложенными
- Передача функции в качестве аргумента другой функции
- Область видимости переменных функции
- Операторы global и nonlocal
- Параметры (аргументы) функции
- Ключевые аргументы в определении функции Python
- Значение аргумента по умолчанию в функциях Python
- Варианты передачи аргументов в функцию Python
- Переменные аргументов *args и **kwargs в функции Python
- Распаковка аргументов для передачи в функцию Python
- Как оцениваются аргументы при вызове функции?
- Строгие правила передачи аргументов в функцию Python
- Инструкция return
- Анонимные функции (lambda-выражения)
- Строки документации в функциях Python
- Рекурсия
- Замыкания в функциях Python
- Перегрузка функций
