В какой момент создается локальное пространство имен для функции
Перейти к содержимому

В какой момент создается локальное пространство имен для функции

  • автор:

Пространство имен и область видимости в классах

В определения классов происходят некоторые хитрые трюки с пространствами имен. Знание того, как работают пространства имен в объектах полезно для любого продвинутого программиста на Python.

Пространство имен — это отображение имен, определенных в объектах. Большинство пространств имен в настоящее время реализованы в виде словарей Python, но это обычно не заметно, кроме производительности, в будущем оно может измениться.

Примерами пространств имен являются:

  • набор встроенных имен, содержащих такие функции, как abs() и имена встроенных исключений;
  • глобальные переменные в модуле;
  • локальные имена переменных в вызове функции.

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

В языке Python используется слово атрибут для любого имени, следующего за точкой. Например, в выражении z.real , real — это атрибут объекта z . Строго говоря, ссылки на имена переменных, классов и функций в модулях — это ссылки на атрибуты. В выражении modname.funcname , modname — это объект модуля, а funcname — его атрибут. В этом случае происходит прямое сопоставление между атрибутами модуля и глобальными именами, определенными в модуле, они используют одно и то же пространство имен!

Атрибуты могут быть доступны для чтения или записи. В последнем случае возможно присвоение значений атрибутам. Для атрибутов модуля, доступных для записи можно написать modname.the_answer = 42 . Атрибуты, доступные для записи, также могут быть удалены с помощью оператора del . Например, del modname.the_answer удаляет атрибут the_answer из объекта с именем modname .

Пространства имен создаются в разные моменты времени и имеют разное время жизни. Пространство имен, содержащее встроенные имена (имена встроенных функций, имена встроенных исключений и т.д.), создается при запуске интерпретатора Python и никогда не удаляется. Глобальное пространство имен для модуля создается при чтении определения модуля, обычно пространства имен модулей также сохраняются до завершения работы интерпретатора. Операторы, выполняемые вызовом интерпретатора верхнего уровня, считываются из файла сценария или в интерактивном режиме, считаются частью модуля с именем __main__ , поэтому они имеют свое собственное глобальное пространство имен с префиксом __main__ в точечной нотации. Встроенные имена на самом деле, также живут в модуле, такое пространство имен называется builtins .

Локальное пространство имен для функции создается при вызове функции и удаляется, когда функция возвращает или создает исключение, которое не обрабатывается внутри функции. На самом деле, забвение было бы лучшим способом описать то, что происходит на самом деле. Рекурсивные вызовы имеют свое собственное локальное пространство имен.

Область видимости — это текстовая область программы Python, в которой пространство имен доступно непосредственно. “Непосредственно доступный » здесь означает, что безусловная ссылка на имя пытается найти имя в пространстве имен.

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

  1. Самая внутренняя область, которая ищется первой, содержит локальные имена. Области видимости любых вложенных функций, поиск которых начинается с ближайшей охватывающей области, содержит нелокальные, но также и неглобальные имена.
  2. Следующая за последней область содержит глобальные имена текущего модуля.
  3. Самая внешняя область (последний поиск) — это пространство имен, содержащее встроенные имена.

Если имя перемененной объявлено глобальным global , то все ссылки и присвоения переходят непосредственно в среднюю область — [2], содержащую глобальные имена модуля. Для повторного связывания переменных, найденных вне внутренней области (вложенные функции), можно использовать нелокальный оператор nonlocal . Если переменные не являются локальными, то эти переменные доступны только для чтения. Попытка записи в такую переменную просто создаст новую локальную переменную в самой внутренней области, оставив внешнюю переменную с идентичным именем неизменной.

Обычно локальная область ссылается на локальные имена (текстуально) текущей функции. Вне функций локальная область ссылается на то же пространство имен, что и глобальная область — пространство имен модуля. Определения классов помещают в локальную область еще одно пространство имен.

Важно понимать, что области видимости определяются текстуально: глобальная область видимости функции, определенной в модуле, является пространством имен этого модуля, независимо от того, откуда и под каким псевдонимом вызывается функция. С другой стороны, фактический поиск имен выполняется динамически во время выполнения, однако определение языка эволюционирует в сторону статического разрешения имен во время “компиляции”, поэтому не полагайтесь на динамическое разрешение имен! На самом деле локальные переменные уже определены статически.

Особенность Python заключается в том, что если нет глобального global или нелокального nonlocal оператора — присвоения имен всегда идут в самую внутреннюю область. Присвоение не копируют данные, они просто привязывают имена к объектам. То же самое верно и для удалений. Оператор del x удаляет привязку x из пространства имен, на которое ссылается локальная область. Фактически все операции, вводящие новые имена, используют локальную область: в частности, операторы импорта и определения функций связывают имя модуля или функции в локальной области.

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

Пример:

Пример отчетливо показывает динамическую сущность языка Python, последовательность поиска имен переменных, а так же демонстрирует, как ссылаться на различные области видимости в пространстве имен.

def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam) 

Выходные данные примера кода:

# After local assignment: test spam # After nonlocal assignment: nonlocal spam # After global assignment: nonlocal spam # In global scope: global spam 

Обратите внимание, что локальное присвоение spam = «local spam» во внутренней функции do_local() не изменило значение spam , присвоенное во внешней функции scope_test . Нелокальное nonlocal присвоение spam = «nonlocal spam» во внутренней функции do_nonlocal() изменило значение spam , а глобальное global присвоение spam = «global spam» во внутренней функции do_global() изменило значение spam на уровне модуля.

Обратите внимание, что перед выполнением функции scope_test() не было никакого присвоения значения для переменной spam . Использование оператора global во внутренней функции do_global() восстановил переменную spam в глобальной области видимости, прежде чем она вывелась на печать!

  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Пространство имен и область видимости в классах
  • Определение классов
  • Объект класса и конструктор класса
  • Создание экземпляра класса
  • Метод экземпляра класса
  • Что такое метод класса и зачем нужен
  • Что такое статический метод в классах Python и зачем нужен
  • Атрибуты класса и переменные экземпляра класса
  • Кэширование методов экземпляра декоратором lru_cache
  • Закрытые/приватные методы и переменные класса Python
  • Наследование классов
  • Множественное наследование классов
  • Абстрактные классы
  • Перегрузка методов в классе Python
  • Перегрузка операторов в классах Python
  • Что такое миксины и как их использовать
  • Класс Python как структура данных, подобная языку C
  • Создание пользовательских типов данных
  • Специальные (магические) методы класса Python
  • Базовая настройка классов Python магическими методами
  • Настройка доступа к атрибутам класса Python
  • Дескриптор класса для чайников
  • Протокол дескриптора класса
  • Практический пример дескриптора
  • Использование метода .__new__() в классах Python
  • Специальный атрибут __slots__ класса Python
  • Специальный метод __init_subclass__ класса Python
  • Определение метаклассов metaclass
  • Эмуляция контейнерных типов в классах Python
  • Другие специальные методы класса
  • Как Python ищет специальные методы в классах
  • Шаблон проектирования Фабрика и его реализация

Python namespaces

Пространства имен создаются в разные моменты и имеют разное время жизни. Пространство имен, содержащее встроенные имена, создается при запуске интерпретатора Python и никогда не удаляется. Глобальное пространство имен для модуля создается при считывании определения модуля; обычно пространства имен модулей существуют до завершения работы интерпретатора. Операторы, выполняемые при вызове интерпретатора, либо считываеме из файла сценария, либо интерактивно, считаются частью модуля с именем __main__ , поэтому у них есть собственное глобальное пространство имен. Встроенные имена фактически также находятся в модуле.

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

Область видимости (scope) — это текстовая область программы Python, где пространство имен доступно непосредственно. «Непосредственно доступный» здесь означает, что неквалифицированная ссылка на имя пытается найти имя в данном пространстве имен.

Хотя области видимости определяются статически, они используются динамически. В любой момент во время выполнения есть 3 или 4 вложенных области, чьи пространства имен доступны напрямую:

  • самая внутренняя (innermost) область видимости, которая ищется первой, содержит локальные имена
  • области видимости любых включающих функций (если таковые имеются), поиск которых начинается с ближайшей бласти видимости. Здесь содержатся нелокальные, но также и неглобальные имена
  • предпоследняя область содержит глобальные имена текущего модуля
  • самая внешняя область видимости (поиск обращается к ней в последюю очередь) — это пространство имен, содержащее встроенные имена

Если имя объявлено глобально, то тогда все ссылки и назначения переходят непосредственно в область, содержащую глобальные имена модуля. Чтобы повторно привязать переменные, которые необходимо видеть за пределами innermost области, можно использовать nonlocal ; если они не объявлены нелокальными, эти переменные доступны только для чтения (попытка записи в такую переменную просто создаст новую локальную переменную во внутренней области видимости, а внешняя переменная с таким же именем останется неизменной).

Обычно локальная область видимости ссылается на локальные имена текущей (буквальной) функции. За пределами функций локальная область видимости ссылается на то же пространство имен, что и глобальная область видимости: на пространство имен модуля. Определения классов помещают еще одно пространство имен в локальную область видимости.

Важно понимать, что области видимости определяются буквально: глобальная область видимости функции, определенной в модуле, является пространством имен этого модуля, независимо от того, откуда и под каким псевдонимом вызывается функция. С другой стороны, фактический поиск имен выполняется динамически во время выполнения — однако определение языка эволюционирует в сторону статического разрешения имен во время «компиляции», поэтому не стоит полагаться на динамическое разрешение имен. Фактически, локальные переменные уже определены статически.

Особенность Python заключается в том, что если не действует ни один global или nonlocal оператор — присвоения имен всегда попадают в самую внутреннюю область видимости. Назначения не копируют данные — они просто связывают имена с объектами. То же самое верно и для удалений: оператор del x удаляет привязку x из пространства имен, на которое ссылается локальная область видимости. Фактически, все операции, которые вводят новые имена, используют локальную область видимости: в частности, операторы импорта и определения функций связывают имя модуля или функции в локальной области.

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

>>> def scope_test(): . def do_local(): . spam = "local spam" . def do_nonlocal(): . nonlocal spam . spam = "nonlocal spam" . def do_global(): . global spam . spam = "global spam" . spam = "test spam" . do_local() . print("After local assignment:", spam) . do_nonlocal() . print("After nonlocal assignment:", spam) . do_global() . print("After global assignment:", spam) >>> spam = 'spam' >>> scope_test() After local assignment: test spam After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam >>> print("In global scope:", spam) In global scope: global spam 
  • [python-standart-library]
  • [python-datamodel]

В какой момент создается локальное пространство имен для функции

Скачай курс
в приложении

Перейти в приложение
Открыть мобильную версию сайта

© 2013 — 2024. Stepik

Наши условия использования и конфиденциальности

Get it on Google Play

Public user contributions licensed under cc-wiki license with attribution required

Пространство имен и область видимости в Python

Последняя строка «Дзен Питона» гласит: «Пространства имен — отличная штука! Давайте будем использовать ее чаще!» . Что же это за загадочные пространства имен? Давайте сначала узнаем, что такое имя.

Примечание. Если не читали «Дзен Питона», введите import this в интерпретаторе.

Например, когда мы присваиваем a = 2 , 2 — это объект, хранящийся в памяти, а a — это имя, с которым мы его связываем. Мы можем получить адрес объекта в ОЗУ с помощью встроенной функции id () . Давайте посмотрим, как ей пользоваться. Имя (оно же идентификатор) — это просто название, данное объекту. В Python всё — объекты, а имя — это способ доступа к объекту.

# Примечание: вы можете получить другие значения id. a = 2 print('id(2) =', id(2)) print('id(a) =', id(a))

Вывод:

id(2) = 9302208
id(a) = 9302208

Здесь оба аргумента ссылаются на 2 , поэтому у них одинаковый id. Давайте сделаем задачу немного интереснее.

# Примечание: вы можете получить другие значения id. a = 2 print('id(a) =', id(a)) a = a+1 print('id(a) =', id(a)) print('id(3) =', id(3)) b = 2 print('id(b) =', id(b)) print('id(2) =', id(2)) 

Вывод:

id(a) = 9302208
id(a) = 9302240
id(3) = 9302240
id(b) = 9302208
id(2) = 9302208

Что происходит в программе выше? Давайте рассмотрим это на диаграмме:

Сначала создается объект 2 и с ним связывается имя a . Когда мы обновляем значение a = a + 1 , создается новый объект 3 , и теперь уже a ссылается на этот объект.

Обратите внимание, что id (a) и id (3) выдают одинаковые значения.

Кроме того, когда выполняется строка b = 2 , новое имя b связывается с предыдущим объектом 2 .

Это эффективное решение, поскольку Python не нужно создавать дубликаты объектов. Такая динамическая привязка имен и делает Python мощным. Также имя может относиться к любому типу объекта.

>>> a = 5 >>> a = 'Привет, мир!' >>> a = [1,2,3] 

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

def printHello(): print("Привет!") a = printHello a() 

Вывод:

Привет!

Как видите, имя a может ссылаться на функцию и мы можем вызывать ее, используя это имя.

Что такое пространство имен

Теперь, когда мы понимаем, что такое имена, мы можем перейти к понятию пространства имен.

Проще говоря, пространство имен — это набор имен.

В Python вы можете представить себе пространство имен в виде отображения каждого имени, которое вы определили, на соответствующие объекты.

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

Пространство имен, содержащее все встроенные имена, создается при запуске интерпретатора Python и существует, пока интерпретатор не завершит работу.

По этой причине встроенные функции, такие как id () , print () и т. д., всегда доступны из любой части программы.

Каждый модуль создает свое собственное глобальное пространство имен.

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

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

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

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

Область видимости — это часть программы, из которой можно получить доступ к пространству имен напрямую, без какого-либо префикса.

В любой момент работы программы существует как минимум три области видимости:

  • область видимости текущей функции, имеющей локальные имена;
  • область видимости модуля, имеющего глобальные имена;
  • самая внешняя область видимости, хранящая встроенные имена.

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

Если внутри одной функции определена другая, то пространство имен последней будет вложено в локальное пространство первой.

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

def outer_function(): b = 20 def inner_function(): c = 30 a = 10 

Здесь переменная a находится в глобальном пространстве имен. Переменная b находится в локальном пространстве имен outer_function () , а c находится во вложенном локальном пространстве имен inner_function () .

Когда мы находимся в inner_function () , c является для нас локальной переменной, b нелокальной, а a — глобальной. Мы можем получить доступ к значениям всех трех переменных a , b и c , однако изменять значение мы можем только у c .

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

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

def outer_function(): a = 20 def inner_function(): a = 30 print('a = ', a) inner_function() print('a = ', a) a = 10 outer_function() print('a = ', a) 

Вывод:

a = 30
a = 20
a = 10

В этой программе три разные переменные a определены в отдельных пространствах имен. А в следующей программе не так.

def outer_function(): global a a = 20 def inner_function(): global a a = 30 print('a = ', a) inner_function() print('a = ', a) a = 10 outer_function() print('a = ', a) 

Вывод:

a = 30
a = 30
a = 30

Здесь все обращения и объявления относятся к глобальной переменной a благодаря ключевому слову global.

СodeСhick.io — простой и эффективный способ изучения программирования.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *