Области видимости переменных и пространства имен в Python
В этом уроке вы узнаете, как работают области видимости переменных в Python. После изучения руководства у вас будет четкое представление о встроенных, локальных и глобальных областях видимости.
- Что такое области видимости переменных в Python?
- Глобальные области
- Локальные области
- Поиск переменных
- Ключевое слово global
Что такое области видимости переменных в Python?
Когда вы присваиваете объект переменной, переменная будет ссылаться на этот объект в памяти. И это говорит о том, что переменная привязана к объекту. После присвоения вы можете получить доступ к объекту, используя имя переменной в различных частях вашего кода. Однако вы не можете получить доступ к переменной повсюду в коде.
Имя переменной и ее привязка (имя и объект) существуют только в определенных частях вашего кода. Часть кода, в которой вы определяете имя/привязку, называется лексической областью действия переменных.
Python хранит эти привязки в так называемых пространствах имен. Каждая область имеет свое собственное пространство имен. И вы можете думать, что пространство имен — это таблица, содержащая метку и ссылку, к которой привязана метка.
Глобальные области
Глобальная область видимости — это, по сути, область видимости модуля. Глобальная область действия охватывает только один файл исходного кода Python. Python не имеет по-настоящему глобальной области видимости, охватывающей все модули, за исключением встроенной области.
Встроенная область — это специальная область, которая предоставляет глобально доступные объекты, такие как print, len, None, True и False. По сути, встроенные и глобальные переменные существуют повсюду внутри модуля.
Внутренне глобальные области вложены во встроенную область:
Если вы получаете доступ к переменной из области, а Python не находит ее в пространстве имен этой области, он будет искать в пространстве имен охватывающей области.
Предположим, что у вас есть следующий оператор в модуле app.py:
print('Hello')
В этом модуле app.py Python ищет функцию print в области модуля(app.py).
Поскольку Python не находит определение функции print в области модуля app.py, Python обращается к охватывающей области, которая является встроенной областью, и ищет там данную функцию. В этом случае он может найти функцию print во встроенной области.
Если вы измените оператор на следующий, вы получите ошибку времени выполнения:
print(counter)
В этом примере Python не находит counter в текущей глобальной области видимости. Поэтому Python ищет его во внешней области, которая является встроенной.
Однако счетчик переменных не существует во встроенной области. Поэтому Python выдает исключение NameError:
NameError: name 'counter' is not defined
Локальные области
При создании функции вы можете определить параметры и переменные для функции. Например:
def increment(counter, by=1): result = counter + by return result
Когда вы выполняете код, Python выполняет две фазы: компиляцию и выполнение.
Когда Python компилирует файл, он добавляет функцию increment() в глобальную область видимости. Кроме того, Python определяет, что переменные counter, by и result внутри функции increment() будут локальными для функции increment(). И Python не будет создавать переменные counter, by и result до тех пор, пока функция не будет выполнена.
Каждый раз, когда вы вызываете функцию, Python создает новую область видимости. Python также присваивает этой области переменные, определенные внутри функции. И эта область называется локальной областью функции или локальной областью действия.
В нашем примере, когда вы вызываете функцию increment():
increment(10,2)
… Python создает локальную область видимости для вызова функции increment().
Кроме того, Python создает локальные переменные counter, by и result в локальном пространстве имен и привязывает их к значениям 10, 2 и 12.
Когда функция завершится, Python удалит локальную область. И все локальные переменные, такие как переменные counter, by и result, выходят за рамки. Если вы попытаетесь получить доступ к этим переменным снаружи функции increment(), вы получите сообщение об ошибке.
И если вы снова вызовете функцию increment():
increment(100,3)
… Python создает новую локальную область видимости и переменные, включая counter, by и result, и привязывает их к значениям 100, 3 и 103.
Поиск переменных
В Python области видимости являются вложенными. Например, локальные области вложены в область модуля. Области модулей вложены во встроенную область видимости:
Когда вы получаете доступ к объекту, привязанному к переменной, Python пытается найти объект:
- сначала в текущей локальной области
- затем переходит вверх по цепочке охватывающих областей, если не находит объект в текущей области.
Ключевое слово global
Когда вы извлекаете значение глобальной переменной из функции, Python автоматически выполняет поиск в пространстве имен локальной области и вверх по цепочке всех включающих ее пространств имен. Например:
counter = 10 def current(): print(counter) current()
В этом примере, когда функция current() выполняется, Python ищет переменную counter в локальной области.
Поскольку Python не находит ее, он ищет переменную в глобальной области видимости. В этом случае Python может найти переменную-счетчик в глобальной области видимости.
Однако если вы присвоите значение глобальной переменной изнутри функции, Python вместо этого поместит эту переменную в локальное пространство имен. Например:
counter = 10 def reset(): counter = 0 print(counter) reset() print(counter)
Выход:
0 10
Во время компиляции Python интерпретирует counter как локальную переменную.
Когда функция reset() запущена, Python находит счетчик в локальной области. Оператор print(counter) внутри функции reset() показывает значение counter, равное нулю. Когда мы печатаем counter после завершения функции reset(), вместо этого он показывает 10.
В этом примере локальная переменная counter маскирует глобальную переменную counter. Если вы хотите получить доступ к глобальной переменной изнутри функции, вы можете использовать ключевое слово global.
Например:
counter = 10 def reset(): global counter counter = 0 print(counter) # 0 reset() print(counter) # 0
Выход:
0 0
В этом примере следующее утверждение:
global counter
… сообщает Python, что переменная counter привязана к глобальной, а не локальной области.
Обратите внимание: не рекомендуется обращаться к глобальной переменной внутри функции.