Информация, полученная из документов
Относительно разрешение имен документация не совсем ясна.Он использует термины scope и namespace , но не дает точных сведений о том, как они вступают в силу и когда в точности возникает NameError
:
Когдаимя используется в блоке кода, оно разрешается с использованием ближайшей области видимости.Набор всех таких областей видимости для блока кода называется средой блока.
Если имя не найдено вообще, возникает исключение NameError
.
Этооднако не объясняет, где именно имя ищется.Относительно пространств имен мы получаем следующую информацию:
Имена разрешаются в пространстве имен верхнего уровня путем поиска в глобальном пространстве имен, то есть в пространстве имен модуля, содержащего блок кода, [...]
И далее, относительно __main__
:
Пространство имен для модуля создается автоматически при первом импорте модуля.Основной модуль для скрипта всегда называется __main__
.
В этой части документа далее указывается, что
'__main__'
являетсяимя области, в которой выполняется код верхнего уровня.
Соответствующий код
Объединяя вышеприведенные операторы, я предполагаю, что всякий раз, когда имя должно быть разрешено в "среда сценариев верхнего уровня " (" пространство имен верхнего уровня ") это происходит путем проверки sys.modules['__main__']
(аналогично тому, как работает доступ к атрибутам для модулей и как он может быть изменен, как указано в PEP 562 ).Однако следующий фрагмент показывает, что это не так:
import sys
class Wrapper:
def __init__(self):
self.main = sys.modules['__main__']
def __getattr__(self, name):
try:
return getattr(self.main, name)
except AttributeError:
return 'Fallback for "{}"'.format(name)
sys.modules['__main__'] = Wrapper()
print(undefined)
, что повышает NameError: name 'undefined' is not defined
.
С другой стороны, мы можем добавлять имена, изменяя sys.modules['__main__'].__dict__
или используя setattr
:
import sys
# Either ...
sys.modules['__main__'].__dict__['undefined'] = 'not anymore'
# Or ...
setattr(sys.modules['__main__'], 'undefined', 'not anymore')
print(undefined) # Works.
Так что я подозревал, что, возможно, это атрибут __dict__
модуля (или эквивалентно __builtins__.globals
), который проверяется напрямую, обходя getattr
объекта модуля.Однако расширение приведенного выше примера показывает, что это не так:
import sys
class Wrapper:
def __init__(self):
self.main = sys.modules['__main__']
def __getattr__(self, name):
try:
return getattr(self.main, name)
except AttributeError:
return 'Fallback for "{}"'.format(name)
@property
def __dict__(self):
class D:
def __contains__(*args):
return True
def __getitem__(__, item):
return getattr(self, item)
return D()
sys.modules['__main__'] = Wrapper()
sys.modules['builtins'].globals = lambda: sys.modules['__main__'].__dict__
print(globals()['undefined']) # Works.
print(undefined) # Raises NameError.
Вопросы
- Какое точное определение областей и пространств имен?
- Как точно разрешаются имена (какие шаги предпринимаются и какие ресурсы проверяются, чтобы определить, существует ли имя)?
- Каким образом для разрешения имен используются области ипространства имен?
- Почему в приведенном выше примере с использованием
Wrapper
происходит сбой (хотя он работает при «общем» доступе к атрибутам модуля, согласно PEP 562 )?