Начнем с образца кода. Сохраните следующий код в файл и запустите его:
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 был нужен для всех глобальных ссылок, мы бы использовали его всегда. Вы должны объявить глобальными все ссылки на встроенную функцию или компонент импортируемого модуля.
0 комментариев
Добавить комментарий