Области видимости переменных

На предыдущих занятиях я иногда произносил фразы: локальная переменная, глобальная переменная. Давайте теперь подробнее разберемся что это за переменные и как с ними работать.

Если сказать по простому, то

Глобальная переменная – это переменная доступная в любом месте программы.

Как можно ее задать? Очень просто – в начале текстового файла, например:

a = 5
N = (100, )
WIDTH, HEIGHT = (1000, 500)

Однако, использование глобальных переменных считается плохим стилем программирования. И допускается, разве что, задавать глобальные константы, используемые во всей программе. А имена констант записывать заглавными буквами, чтобы отличать их от обычных не глобальных (то есть, локальных) переменных.

Локальные переменные – это переменные, объявленные внутри любого блока программы.

Например:

def myFunc(b):
    for x in range(b):
        n = x+1
        print(n, end=" ")
 
myFunc(6)

Здесь у нас сразу три локальных переменных: b, n, x. Почему локальные? Дело в том, что они доступны только внутри функции myFunc и не существуют за ее пределами. Если мы попытаемся после функции выполнить операцию, например:

print(x)

то возникнет ошибка, что x не существует. А вот внутри функции все три переменные существуют:

print(b, n, x)

Обратите внимание, здесь цикл for не образует своих локальных переменных, как это происходит, например, в С++ или Java, и вот эта переменная n продолжает существовать и за его пределами.

Ну, хорошо, а как мы можем работать с глобальной переменной внутри этой функции? Если написать вот такую конструкцию:

def myFunc(b):
    a = 10
    for x in range(b):
        n = x+1
        print(n, end=" ")

и после вызова этой функции вывести значение переменной a:

myFunc(6)
print("\n\n%d"%(a))

то увидим прежнее значение 5. Почему? Дело в том, что когда мы присвоили a=10, то внутри функции была создана локальная переменная с таким же именем a и на значение глобальной переменной это никак не повлияло.

Более наглядный пример использования локальной переменной с тем же именем, что и глобальная, такой:

name = "Tom"
 
def say_hi():
    print("Hello", name)
 
def say_bye():
    name = "Bob"
    print("Good bye", name)
 
say_hi()
say_bye()

В консоли увидим:

Hello Tom
Good bye Bob

То есть, первая функция использовала глобальную переменную name, т.к. никакой другой для нее не существовало, а вторая функция использовала локальную name, объявленную внутри нее. Этот пример показывает, что функция сначала пытается найти нужную переменную внутри собственной области видимости, и если не находит, то переходит на более высокий уровень, в данном случае – глобальной области.

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

global a

тем самым мы указываем, что хотим работать с глобальной a, а не создавать локальную переменную. Теперь, при выполнении этой программы, мы видим измененное значение глобальной переменной a.

Однако, здесь следует быть аккуратным, так как если в функции уже была создана локальная a, то конструкция global приведет к ошибке:

    a = 5
    global a

Так можно делать только в отсутствии соответствующих локальных переменных.

Или же, если глобальная переменная a не существует и внутри функции мы выполняем эти операции, то будет создана глобальная переменная с соответствующим значением.

В Python имеется один интересный режим работы с локальными переменными с использованием ключевого слова nonlocal. Давайте предположим, что у нас имеется объявление одной функции внутри другой:

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print("inner:", x)
 
    inner()
    print("outer:", x)
 
outer()
print("global:", x)

При запуске программы мы увидим ожидаемые результаты:

inner: 2
outer: 1
global: 0

А теперь внутри функции inner мы скажем, что хотим работать с переменной x, объявленной уровнем выше, то есть, внутри функции outer:

nonlocal x

Теперь строка x=2 будет означать изменение переменной x в функции outer и при запуске программы получим результаты:

inner: 2
outer: 2
global: 0

Но так можно делать только с локальными переменными. С глобальной работать не будет. Если мы пропишем строчку

nonlocal x

в функции outer, то возникнет ошибка, т.к. уровнем выше находится уже глобальная область. Здесь, вместо nonlocal следует уже использовать global:

global x

а nonlocal в inner убрать, иначе опять же получится ссылка на глобальную переменную.

Итак, на этом занятии мы с вами рассмотрели глобальную и локальную области видимости переменных и познакомились с ключевыми словами global и nonlocal.

Видео по теме