Локальные и глобальные области видимости в Python

  • 20 марта, 12:22
  • 4051
  • 0

Начнем с образца кода. Сохраните следующий код в файл и запустите его:

command = "You are a LOVELY person!"

def shout():
    print(command)

shout()
print(command)

Вывод:

You are a LOVELY person!
You are a LOVELY person!

Все работает как ожидалось. Немного изменим код и снова запустим:

command = "You are a LOVELY person!"

def shout():
    command = "HI!"
    print(command)

shout()
print(command)

Вывод:

HI!
You are a LOVELY person!

Все еще работает. Изменим код еще немного и запустим снова:

command = "You are a LOVELY person!"

def shout():
    command = "HI!"
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вывод:

HI!
You are a LOVELY person!

Вывод теперь не столь интуитивно ожидаемый. Сделаем последнее изменение, прежде чем его обсудить:

command = "You are a LOVELY person!"

def shout():
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вывод:

Traceback (most recent call last):
  File "prog.py", line 8, in <module>
    shout()
  File "prog.py", line 4, in shout
    print(command)
UnboundLocalError: local variable 'command' referenced before assignment

ВОУ! Что это? У нас есть переменная command, объявленная и инициализирована в первой строке файла. Это может сбить с толку многих Python программистов. Однако, если вы знакомы с тем, как Python обрабатывает области видимости переменных, вас ничего не должно удивить.

В последнем примере, который работал нормально, возможно, вы ожидали, что вывод будет следующим:

HI!
You are amazing!!

Причина ожидания этого вывода проста. Мы меняем значение переменной command, присваивая ей «You are amazing !!» в функции. Это не работает так, как ожидалось, поскольку мы меняем значение command в области видимости функции shout. Изменение остается в пределах этой функции. Как только мы выбираемся из этой функции в глобальную область видимости, command указывает на свое прежнее глобальное значение.

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

command = "You are a LOVELY person!"

def shout():
    print(command)

shout()
print(command)

Однако, если мы изменим значение переменной или ее назначения неоднозначным способом, Python выдаст нам ошибку. Посмотрите на прошлый код:

command = "You are a LOVELY person!"

def shout():
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Проблема возникает, когда Python ищет command в области видимости shout, а находит ее объявленной и инициализирован ПОСЛЕ того, как мы пытаемся вывести ее значение. В этот момент Python не знает, какое из значений command мы хотим вывести.

Мы можем исправить эту проблему, явно указав Python, что мы хотим вывести значение глобальной command, и хотим изменить эту глобальную переменную. Измените код следующим образом:

command = "You are a LOVELY person!"

def shout():
    global command
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вывод:

You are a LOVELY person!
You are amazing!!

Надо держаться подальше от глобальных переменных, поскольку если быть неосторожным, можно получить неожиданные результаты. Следует использовать global только тогда, когда невозможно обойтись использованием возвращаемых значений, и переменными класса.

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

Какие правила для локальных и глобальных переменных в Python?

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

С одной стороны, global обеспечивает барьер против непредвиденных побочных эффектов. С другой стороны, если бы global был нужен для всех глобальных ссылок, мы бы использовали его всегда. Вы должны объявить глобальными все ссылки на встроенную функцию или компонент импортируемого модуля.


Теги: код python
Banner
0 комментариев
Сортировка:
Добавить комментарий