Сообщить об ошибке.

Инструкции 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()