MyTetra Share
Делитесь знаниями!
Область видимости в Python
20.01.2018
15:16
Текстовые метки: Python,python-scripts.com,Область видимости
Раздел: Python - python-scripts.com

python-scripts.com

Область видимости в Python

автор

8-11 минут


Вы, наверное, не раз слышали термин область видимости, когда изучали программирование. Это весьма важная тема, незнание которой может привести к достаточно запутанным ошибкам. Область видимости указывает интерпретатору, когда наименование (или переменная) видимо. Другими словами, область видимости определяет, когда и где вы можете использовать свои переменные, функции, и т.д. Если вы попытаетесь использовать что-либо, что не является в вашей области видимости, вы получите ошибку NameError.

Python содержит три разных типа области видимости:

  • Локальная область видимости
  • Глобальная область видимости
  • Нелокальная область видимости (была добавлена в Python 3)

Локальная область видимости

Локальная область видимости наиболее часто используется в Python. Когда мы создаем переменную в блоке кода, она будет разрешена при помощи ближайшей области видимости, или областей. Группирование всех этих областей известно как среда блоков кода. Другими словами, все назначения выполняются в локальной области по умолчанию. Если вам нужно что-то другое, тогда вам нужно настроить свою переменную на глобальную или нелокальную область, которые мы рассмотрим немного позже. Сейчас мы создадим простой пример, используя интерпретатор Python, в котором демонстрируется назначение локальной области видимости.


x = 10

def my_func(a, b):

    print(x)

    print(z)

my_func(1, 2)

Результат


10

Traceback (most recent call last):

    File "<pyshell#19>", line 1, in <module>

        my_func(1, 2)

    File "<pyshell#18>", line 3, in my_func

        print(z)

NameError: name 'z' is not defined

Здесь мы создаем переменную х и очень простую функцию, которая принимает два аргумента. Далее она выводит х и z. Обратите внимание на то, что мы не определили z, так что когда мы вызываем функцию, мы получаем ошибку NameError. Это происходит в связи с тем, что z не определена, или находится вне области видимости. Если вы определите z перед вызовом функции, тогда она будет найдена и ошибка NameError не возникнет. Ошибка NameError также возникает при попытке получения доступа к переменной, которая находится только внутри функции:


def my_func(a, b):

    i = 2

    print(x)

if __name__ == '__main__':

    x = 10

    my_func(1, 2)

    print(i)

Переменная i определена только внутри функции, так что при запуске кода мы получаем ошибку NameError. Давайте немного модифицируем первый пример. Разместим данный код в python-файл и попытаемся его запустить:


def my_func(a, b):

    x = 5

    print(x)

if __name__ == '__main__':

    x = 10

    my_func(1, 2)

    print(x)

  1. Что, по-вашему, должно произойти?
  2. Выдаст ли код цифру 10 дважды?

Нет, не выдаст. Причина в том, что мы имеем две переменные х. Переменная х внутри my_func имеет локальную область видимости функции и переопределяет переменную х вне функции. Так что когда мы вызываем функцию my_func, в выдаче мы видим 5, а не 10. Затем, когда функция возвращается, переменная х внутри функции my_func является кучей мусора и область для выдачи х срабатывает еще один раз. По этой причине последний оператор выдачи выдает именно 10. Если вы хотите кое-что поинтереснее, вы можете попытаться вывести х перед тем как назначить его в нашей функции:


def my_func(a, b):

    print(x)

    x = 5

    print(x)

if __name__ == '__main__':

    x = 10

    my_func(1, 2)

    print(x)

Кода вы запустите этот код, вы получите ошибку:


UnboundLocalError: local variable 'x' referenced before assignment

Это происходит потому, что Python замечает, что вы назначаете х в функцию my_func позже, что и приводит к ошибке, так как х еще не определен.

Глобальная область видимости

Python содержит оператор global. Это ключевое слово Python. Оператор global объявляет переменную доступной для блока кода, следующим за оператором. Хотя вы и можете создать наименование, перед тем, как объявить его глобальным, я настоятельно не рекомендую этого делать. Давайте попробуем использовать глобальную область для исправления нашей ошибке из предыдущего примера:


def my_func(a, b):

    global x

    print(x)

    x = 5

    print(x)

if __name__ == '__main__':

    x = 10

    my_func(1, 2)

    print(x)

Выдача данного кода должна быть следующей:

Объявляя х как глобальный, мы говорим Python использовать первое объявление х для нашего первого оператора вывода в функции. Далее мы даем х новое значение – а именно 5, и выводим его еще раз, перед тем как выйти из функции. Обратите внимание на то, что х становится глобальной переменной, когда мы доходим до последнего оператора вывода в конце кода, и там х все еще равен 5. Давайте смешаем глобальную и локальную область видимости и поглядим, что из этого получится:


def my_func(a, b):

    global c

    b, a = a, b

    d = 'Mike'

    print(a, b, c, d)

a, b, c, d = 1, 2, 'c is global', 4

my_func(1, 2)

print(a, b, c, d)

Здесь мы назначаем с в качестве глобальной переменной. Таким образом, «с» будет выводиться и внутри и снаружи нашей функции. Мы также меняем местами значения переменных а и b в функции, чтобы показать, что мы можем переназначить их внутри функции, не меняя их вне функции. Это показывает, что переменные а и b не являются глобальными. Если вы запустите этот код, вы увидите следующую выдачу:


2 1 c is global Mike

1 2 c is global 4

Я хочу обратить ваше внимание на то, что не нужно менять глобальные переменные внутри функции. Комьюнити Python объявило такую практику очень нежелательной, так как из-за этого исправление кода становится намного сложнее. Теперь, с пониманием основных принципов локальных и глобальных областей, мы можем перейти к нелокальной области non_local.

Область nonlocal

В Python 3 было добавлено новое ключевое слово под названием nonlocal. С его помощью мы можем добавлять переопределение области во внутреннюю область. Вы можете ознакомиться со всей необходимой на данный счет информацией в PEP 3104. Это наглядно демонстрируется в нескольких примерах. Один из самых простых – это создание функции, которая может увеличиваться:


def counter():

    num = 0

    def incrementer():

        num += 1

        return num

    return incrementer

Если вы попробуете запустить этот код, вы получите ошибку UnboundLocalError, так как переменная num ссылается прежде, чем она будет назначена в самой внутренней функции. Давайте добавим nonlocal в наш код:


def counter():

    num = 0

    def incrementer():

        nonlocal num

        num += 1

        return num

    return incrementer

Результат работы:


c = counter()

print(c) # <function counter.<locals>.incrementer at 0x7f45caf44048>

c() # 1

c() # 2

c() # 3

Теперь наша возрастающая функция работает именно так, как мы от нее и ожидаем. Для заметки, тип такой функции называется closure (дословно – закрытие). Такая функция является блоком кода, который «закрывает» переменные nonlocal. Суть в том, что вы можете ссылать переменные, которые определены вне вашей функции. Обычно, nonlocal позволяет вам назначать переменные во внешней области, но не в глобальной. Так что вы не можете использовать nonlocal в функции подсчета, так как в таком случае она попытается передать функцию глобальной области. Попробуйте, и получите ошибку SyntaxError незамедлительно. Вместо этого, вам нужно использовать nonlocal во вложенной функции.

Подведем итоги

В данной статье мы смогли понять то, как переменная ссылается, используя ключевые слова Python global и nonlocal. Мы узнали, где мы можем их использовать и зачем. Мы также узнали кое-что о локальной области видимости. Хорошего дня и продолжайте экспериментировать!


Так же в этом разделе:
 
MyTetra Share v.0.52
Яндекс индекс цитирования