четверг, 30 ноября 2017 г.

Пространства имен в Python

Namespaces are one honking great idea -- let's do more of those!

The Zen of Python, by Tim Peters

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

Посмотрим на пространства имен Python в интерактивном режиме.

C:\_dev> python.exe
Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> __name__
'__main__'

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

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

Попробуем увидеть, что за ними стоит. Нам помогут цикл for и eval():

>>> for name in dir(): print(name, eval(name), eval('type('+name+')'))
...
__annotations__ {} <class 'dict'>
__builtins__ <module 'builtins' (built-in)> <class 'module'>
__doc__ None <class 'NoneType'>
__loader__ <class '_frozen_importlib.BuiltinImporter'> <class 'type'>
__name__ __main__ <class 'str'>
__package__ None <class 'NoneType'>
__spec__ None <class 'NoneType'>

Приблизительно такую же информацию можно получить при помощи встроенной функции loclas(), которая возвращает словарь с ключами - именами текущего пространства имен:

>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>
, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '__spec__'}

(Заметьте, в пространстве имен появилось имя name, использованное нами выше в качестве переменной в цикле for. И с именем name связано значение, присвоенное ему в цикле последним.)

Наше текущее пространство имен при вводе команд в интерактивном режиме Python - это глобальное пространство имен модуля __main__. Поэтому словарь, возвращаемый функцией globals() и представляющий глобальное пространство имен, совпадает со словарем, возвращаемым locals():


>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>
, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '__spec__'}

>>> locals() == globals()
True

Мы вернемся к разнице между locals() и globals() позднее. А пока посмотрим внимательно на то, что имеется в глобальном пространстве имен.

Под именем __builtins__ в глобальном пространстве имен имеется модуль builtins, который автоматически импортируется при запуске Python. Этот модуль содержит все встроенные функции и классы, в том числе такие знакомые, как int, float, list, а также все встроенные исключения (exceptions):

>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferEr
ror', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'Conne
ctionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsErr
or', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarni
ng', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'Lookup
Error', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplement
edError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionEr
ror', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'Syn
taxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalE
rror', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarni
ng', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__im
port__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray',
'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divm
od', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'ha
sh', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map',
 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr'
, 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'var
s', 'zip']

В нем есть имена функций dir, eval, locals и globals, которыми мы воспользовались выше так, как будто их имена известны в текущем пространстве имен. Дело в том, что имена, не найденные в глобальном пространстве имен, Python ищет в пространстве имен модуля builtins.

Следующие два вызова по сути одно и то же:

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'name']
>>> __builtins__.dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'name']

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

>>> for name in dir(__builtins__): print(name, eval(name), eval('type('+name+')'))
...
ArithmeticError <class 'ArithmeticError'> <class 'type'>
AssertionError <class 'AssertionError'> <class 'type'>
AttributeError <class 'AttributeError'> <class 'type'>
BaseException <class 'BaseException'> <class 'type'>
BlockingIOError <class 'BlockingIOError'> <class 'type'>
BrokenPipeError <class 'BrokenPipeError'> <class 'type'>
BufferError <class 'BufferError'> <class 'type'>
BytesWarning <class 'BytesWarning'> <class 'type'>
ChildProcessError <class 'ChildProcessError'> <class 'type'>
ConnectionAbortedError <class 'ConnectionAbortedError'> <class 'type'>
ConnectionError <class 'ConnectionError'> <class 'type'>
ConnectionRefusedError <class 'ConnectionRefusedError'> <class 'type'>
ConnectionResetError <class 'ConnectionResetError'> <class 'type'>
DeprecationWarning <class 'DeprecationWarning'> <class 'type'>
EOFError <class 'EOFError'> <class 'type'>
Ellipsis Ellipsis <class 'ellipsis'>
EnvironmentError <class 'OSError'> <class 'type'>
Exception <class 'Exception'> <class 'type'>
False False <class 'bool'>
FileExistsError <class 'FileExistsError'> <class 'type'>
FileNotFoundError <class 'FileNotFoundError'> <class 'type'>
FloatingPointError <class 'FloatingPointError'> <class 'type'>
FutureWarning <class 'FutureWarning'> <class 'type'>
GeneratorExit <class 'GeneratorExit'> <class 'type'>
IOError <class 'OSError'> <class 'type'>
ImportError <class 'ImportError'> <class 'type'>
ImportWarning <class 'ImportWarning'> <class 'type'>
IndentationError <class 'IndentationError'> <class 'type'>
IndexError <class 'IndexError'> <class 'type'>
InterruptedError <class 'InterruptedError'> <class 'type'>
IsADirectoryError <class 'IsADirectoryError'> <class 'type'>
KeyError <class 'KeyError'> <class 'type'>
KeyboardInterrupt <class 'KeyboardInterrupt'> <class 'type'>
LookupError <class 'LookupError'> <class 'type'>
MemoryError <class 'MemoryError'> <class 'type'>
ModuleNotFoundError <class 'ModuleNotFoundError'> <class 'type'>
NameError <class 'NameError'> <class 'type'>
None None <class 'NoneType'>
NotADirectoryError <class 'NotADirectoryError'> <class 'type'>
NotImplemented NotImplemented <class 'NotImplementedType'>
NotImplementedError <class 'NotImplementedError'> <class 'type'>
OSError <class 'OSError'> <class 'type'>
OverflowError <class 'OverflowError'> <class 'type'>
PendingDeprecationWarning <class 'PendingDeprecationWarning'> <class 'type'>
PermissionError <class 'PermissionError'> <class 'type'>
ProcessLookupError <class 'ProcessLookupError'> <class 'type'>
RecursionError <class 'RecursionError'> <class 'type'>
ReferenceError <class 'ReferenceError'> <class 'type'>
ResourceWarning <class 'ResourceWarning'> <class 'type'>
RuntimeError <class 'RuntimeError'> <class 'type'>
RuntimeWarning <class 'RuntimeWarning'> <class 'type'>
StopAsyncIteration <class 'StopAsyncIteration'> <class 'type'>
StopIteration <class 'StopIteration'> <class 'type'>
SyntaxError <class 'SyntaxError'> <class 'type'>
SyntaxWarning <class 'SyntaxWarning'> <class 'type'>
SystemError <class 'SystemError'> <class 'type'>
SystemExit <class 'SystemExit'> <class 'type'>
TabError <class 'TabError'> <class 'type'>
TimeoutError <class 'TimeoutError'> <class 'type'>
True True <class 'bool'>
TypeError <class 'TypeError'> <class 'type'>
UnboundLocalError <class 'UnboundLocalError'> <class 'type'>
UnicodeDecodeError <class 'UnicodeDecodeError'> <class 'type'>
UnicodeEncodeError <class 'UnicodeEncodeError'> <class 'type'>
UnicodeError <class 'UnicodeError'> <class 'type'>
UnicodeTranslateError <class 'UnicodeTranslateError'> <class 'type'>
UnicodeWarning <class 'UnicodeWarning'> <class 'type'>
UserWarning <class 'UserWarning'> <class 'type'>
ValueError <class 'ValueError'> <class 'type'>
Warning <class 'Warning'> <class 'type'>
WindowsError <class 'OSError'> <class 'type'>
ZeroDivisionError <class 'ZeroDivisionError'> <class 'type'>
__build_class__ <built-in function __build_class__> <class 'builtin_function_or_method'>
__debug__ True <class 'bool'>
__doc__ None <class 'NoneType'>
__import__ <built-in function __import__> <class 'builtin_function_or_method'>
__loader__ <class '_frozen_importlib.BuiltinImporter'> <class 'type'>
__name__ __main__ <class 'str'>
__package__ None <class 'NoneType'>
__spec__ None <class 'NoneType'>
abs <built-in function abs> <class 'builtin_function_or_method'>
all <built-in function all> <class 'builtin_function_or_method'>
any <built-in function any> <class 'builtin_function_or_method'>
ascii <built-in function ascii> <class 'builtin_function_or_method'>
bin <built-in function bin> <class 'builtin_function_or_method'>
bool <class 'bool'> <class 'type'>
bytearray <class 'bytearray'> <class 'type'>
bytes <class 'bytes'> <class 'type'>
callable <built-in function callable> <class 'builtin_function_or_method'>
chr <built-in function chr> <class 'builtin_function_or_method'>
classmethod <class 'classmethod'> <class 'type'>
compile <built-in function compile> <class 'builtin_function_or_method'>
complex <class 'complex'> <class 'type'>
copyright Copyright (c) 2001-2017 Python Software Foundation.
All Rights Reserved.

Copyright (c) 2000 BeOpen.com.
All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved. <class '_sitebuiltins._Printer'>
credits     Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
    for supporting Python development.  See www.python.org for more information. <class '_sitebuiltins._Printer'>
delattr <built-in function delattr> <class 'builtin_function_or_method'>
dict <class 'dict'> <class 'type'>
dir <built-in function dir> <class 'builtin_function_or_method'>
divmod <built-in function divmod> <class 'builtin_function_or_method'>
enumerate <class 'enumerate'> <class 'type'>
eval <built-in function eval> <class 'builtin_function_or_method'>
exec <built-in function exec> <class 'builtin_function_or_method'>
exit Use exit() or Ctrl-Z plus Return to exit <class '_sitebuiltins.Quitter'>
filter <class 'filter'> <class 'type'>
float <class 'float'> <class 'type'>
format <built-in function format> <class 'builtin_function_or_method'>
frozenset <class 'frozenset'> <class 'type'>
getattr <built-in function getattr> <class 'builtin_function_or_method'>
globals <built-in function globals> <class 'builtin_function_or_method'>
hasattr <built-in function hasattr> <class 'builtin_function_or_method'>
hash <built-in function hash> <class 'builtin_function_or_method'>
help Type help() for interactive help, or help(object) for help about object. <class '_sitebuiltins._Helper'>
hex <built-in function hex> <class 'builtin_function_or_method'>
id <built-in function id> <class 'builtin_function_or_method'>
input <built-in function input> <class 'builtin_function_or_method'>
int <class 'int'> <class 'type'>
isinstance <built-in function isinstance> <class 'builtin_function_or_method'>
issubclass <built-in function issubclass> <class 'builtin_function_or_method'>
iter <built-in function iter> <class 'builtin_function_or_method'>
len <built-in function len> <class 'builtin_function_or_method'>
license Type license() to see the full license text <class '_sitebuiltins._Printer'>
list <class 'list'> <class 'type'>
locals <built-in function locals> <class 'builtin_function_or_method'>
map <class 'map'> <class 'type'>
max <built-in function max> <class 'builtin_function_or_method'>
memoryview <class 'memoryview'> <class 'type'>
min <built-in function min> <class 'builtin_function_or_method'>
next <built-in function next> <class 'builtin_function_or_method'>
object <class 'object'> <class 'type'>
oct <built-in function oct> <class 'builtin_function_or_method'>
open <built-in function open> <class 'builtin_function_or_method'>
ord <built-in function ord> <class 'builtin_function_or_method'>
pow <built-in function pow> <class 'builtin_function_or_method'>
print <built-in function print> <class 'builtin_function_or_method'>
property <class 'property'> <class 'type'>
quit Use quit() or Ctrl-Z plus Return to exit <class '_sitebuiltins.Quitter'>
range <class 'range'> <class 'type'>
repr <built-in function repr> <class 'builtin_function_or_method'>
reversed <class 'reversed'> <class 'type'>
round <built-in function round> <class 'builtin_function_or_method'>
set <class 'set'> <class 'type'>
setattr <built-in function setattr> <class 'builtin_function_or_method'>
slice <class 'slice'> <class 'type'>
sorted <built-in function sorted> <class 'builtin_function_or_method'>
staticmethod <class 'staticmethod'> <class 'type'>
str <class 'str'> <class 'type'>
sum <built-in function sum> <class 'builtin_function_or_method'>
super <class 'super'> <class 'type'>
tuple <class 'tuple'> <class 'type'>
type <class 'type'> <class 'type'>
vars <built-in function vars> <class 'builtin_function_or_method'>
zip <class 'zip'> <class 'type'>

Так, например, eval, any и all являются builtin_function_or_method, а вот filter, map и range являются экземплярами класса type, то есть, классами. (Да ведь это итераторы!)

Следующая попытка разрешить имя pi не удается, потому что это имя не определено в глобальном пространстве имен и не определено в модуле builtins:

>>> pi
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'pi' is not defined

Оно определено в модуле math. Импортируем этот модуль и проверим, что изменилось в текущем пространстве имен:

>>> import math
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math', 'name']

В текущем пространстве имен появилось имя math. Это имя указывает на модуль math:

>>> math
<module 'math' (built-in)>

В котором есть много интересного:

>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'ata
nh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fm
od', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log',
 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

В том числе, интересующее нас имя pi, с которым связано число пи:

>>> math.pi
3.141592653589793

Мы даже можем его переопределить (хотя это хулиганство):

>>> math.pi = 123.123
>>> math.pi
123.123

Вернемся теперь к вопросу о локальном пространстве имен. Чтобы функция locals() вернула словарь для локального пространства имен, нужно вызвать ее внутри нашей собственной функции, где текущее простраство имен - локальное пространство имен этой функции.

>>> def loc():
...     x = 1
...     y = 2
...     print(locals() == globals())
...     print(locals())
...     print(globals())
...
>>> loc()
False
{'y': 2, 'x': 1}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>
, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '__spec__', 'math': <
module 'math' (built-in)>, 'loc': <function loc at 0x0000028B285CAB70>}

Теперь разница между locals() и globals() очевидна.

А в глобальном пространстве имен появилось имя loc, указывающее на определенную нами функцию. Вызовем ее по-другому:

>>> globals()['loc']()
False
{'y': 2, 'x': 1}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>
, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '__spec__', 'math': <
module 'math' (built-in)>, 'loc': <function loc at 0x0000028B285CAB70>}

Можно вызвать и так (ведь на уровне модуля глобальное и локальное пространства имен совпадают):

>>> locals()['loc']()
False
{'y': 2, 'x': 1}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>
, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'name': '__spec__', 'math': <
module 'math' (built-in)>, 'loc': <function loc at 0x0000028B285CAB70>}

А как поживает число пи в модуле math?

>>> locals()['math'].pi
123.123

Прекратим это безобразие и, пожалуй, закончим на сегодня:

>>> quit()

C:\_dev>

2 комментария:

  1. This is a great article. I’m considering this option to grow my reach and get more exposure for my website but I’m not there yet. I’ll bookmark this post for future use. I didn’t finish all the content but I enjoyed every part so far.
    python online training
    python training

    ОтветитьУдалить
  2. Alderney: Alderney Casino | Casino in East Chicago - KT
    The 춘천 출장마사지 Alderney Casino is a 의왕 출장마사지 casino in East Chicago and in East Chicago. 사천 출장마사지 The Alderney Casino is 파주 출장마사지 open daily 24 hours 7 days a 부산광역 출장샵 week.

    ОтветитьУдалить