Namespace
We’ve been hearing about the word namespace
all the time. But what the heck is it really??
- A
namespace
is a mapping fromnames
toobjects
. In python, namespaces are internally implemented asdictionary
. The following are the examples of namespacebuilt-in
namespaceglobal
namespace $($same as module namespace$)$local
namespace
- It’s worth mentioning that
global
namespace is writable which mean you can modify it. However, you cannot modify thelocal
namespace.
built-in
namespace
The module import builtins
gives us direct access to all ‘built-in identifiers such as open()
, __name__
, __doc__
, all()
, any()
, abs()
, all the exceptions
and other built-in identifiers you’ve seen out there!
1
2
import builtins
builtins.__dict__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
{'__name__': 'builtins',
'__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.",
'__package__': '',
'__loader__': _frozen_importlib.BuiltinImporter,
'__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in'),
'__build_class__': <function __build_class__>,
'__import__': <function __import__>,
'abs': <function abs(x, /)>,
'all': <function all(iterable, /)>,
'any': <function any(iterable, /)>,
'ascii': <function ascii(obj, /)>,
'bin': <function bin(number, /)>,
'breakpoint': <function breakpoint>,
'callable': <function callable(obj, /)>,
'chr': <function chr(i, /)>,
'compile': <function compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1, *, _feature_version=-1)>,
'delattr': <function delattr(obj, name, /)>,
'dir': <function dir>,
'divmod': <function divmod(x, y, /)>,
'eval': <function eval(source, globals=None, locals=None, /)>,
'exec': <function exec(source, globals=None, locals=None, /)>,
'format': <function format(value, format_spec='', /)>,
'getattr': <function getattr>,
'globals': <function globals()>,
'hasattr': <function hasattr(obj, name, /)>,
'hash': <function hash(obj, /)>,
'hex': <function hex(number, /)>,
'id': <function id(obj, /)>,
'input': <bound method Kernel.raw_input of <ipykernel.ipkernel.IPythonKernel object at 0x7fd68043b790>>,
'isinstance': <function isinstance(obj, class_or_tuple, /)>,
'issubclass': <function issubclass(cls, class_or_tuple, /)>,
'iter': <function iter>,
'len': <function len(obj, /)>,
'locals': <function locals()>,
'max': <function max>,
'min': <function min>,
'next': <function next>,
'oct': <function oct(number, /)>,
'ord': <function ord(c, /)>,
'pow': <function pow(base, exp, mod=None)>,
'print': <function print>,
'repr': <function repr(obj, /)>,
'round': <function round(number, ndigits=None)>,
'setattr': <function setattr(obj, name, value, /)>,
'sorted': <function sorted(iterable, /, *, key=None, reverse=False)>,
'sum': <function sum(iterable, /, start=0)>,
'vars': <function vars>,
'None': None,
'Ellipsis': Ellipsis,
'NotImplemented': NotImplemented,
'False': False,
'True': True,
'bool': bool,
'memoryview': memoryview,
'bytearray': bytearray,
'bytes': bytes,
'classmethod': classmethod,
'complex': complex,
'dict': dict,
'enumerate': enumerate,
'filter': filter,
'float': float,
'frozenset': frozenset,
'property': property,
'int': int,
'list': list,
'map': map,
'object': object,
'range': range,
'reversed': reversed,
'set': set,
'slice': slice,
'staticmethod': staticmethod,
'str': str,
'super': super,
'tuple': tuple,
'type': type,
'zip': zip,
'__debug__': True,
'BaseException': BaseException,
'Exception': Exception,
'TypeError': TypeError,
'StopAsyncIteration': StopAsyncIteration,
'StopIteration': StopIteration,
'GeneratorExit': GeneratorExit,
'SystemExit': SystemExit,
'KeyboardInterrupt': KeyboardInterrupt,
'ImportError': ImportError,
'ModuleNotFoundError': ModuleNotFoundError,
'OSError': OSError,
'EnvironmentError': OSError,
'IOError': OSError,
'EOFError': EOFError,
'RuntimeError': RuntimeError,
'RecursionError': RecursionError,
'NotImplementedError': NotImplementedError,
'NameError': NameError,
'UnboundLocalError': UnboundLocalError,
'AttributeError': AttributeError,
'SyntaxError': SyntaxError,
'IndentationError': IndentationError,
'TabError': TabError,
'LookupError': LookupError,
'IndexError': IndexError,
'KeyError': KeyError,
'ValueError': ValueError,
'UnicodeError': UnicodeError,
'UnicodeEncodeError': UnicodeEncodeError,
'UnicodeDecodeError': UnicodeDecodeError,
'UnicodeTranslateError': UnicodeTranslateError,
'AssertionError': AssertionError,
'ArithmeticError': ArithmeticError,
'FloatingPointError': FloatingPointError,
'OverflowError': OverflowError,
'ZeroDivisionError': ZeroDivisionError,
'SystemError': SystemError,
'ReferenceError': ReferenceError,
'MemoryError': MemoryError,
'BufferError': BufferError,
'Warning': Warning,
'UserWarning': UserWarning,
'DeprecationWarning': DeprecationWarning,
'PendingDeprecationWarning': PendingDeprecationWarning,
'SyntaxWarning': SyntaxWarning,
'RuntimeWarning': RuntimeWarning,
'FutureWarning': FutureWarning,
'ImportWarning': ImportWarning,
'UnicodeWarning': UnicodeWarning,
'BytesWarning': BytesWarning,
'ResourceWarning': ResourceWarning,
'ConnectionError': ConnectionError,
'BlockingIOError': BlockingIOError,
'BrokenPipeError': BrokenPipeError,
'ChildProcessError': ChildProcessError,
'ConnectionAbortedError': ConnectionAbortedError,
'ConnectionRefusedError': ConnectionRefusedError,
'ConnectionResetError': ConnectionResetError,
'FileExistsError': FileExistsError,
'FileNotFoundError': FileNotFoundError,
'IsADirectoryError': IsADirectoryError,
'NotADirectoryError': NotADirectoryError,
'InterruptedError': InterruptedError,
'PermissionError': PermissionError,
'ProcessLookupError': ProcessLookupError,
'TimeoutError': TimeoutError,
'open': <function io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)>,
'copyright': Copyright (c) 2001-2021 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.,
'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.,
'license': Type license() to see the full license text,
'help': Type help() for interactive help, or help(object) for help about object.,
'execfile': <function _pydev_imps._pydev_execfile.execfile(file, glob=None, loc=None)>,
'runfile': <function _pydev_bundle.pydev_umd.runfile(filename, args=None, wdir=None, namespace=None)>,
'__IPYTHON__': True,
'display': <function IPython.core.display_functions.display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, raw=False, clear=False, **kwargs)>,
'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7fd680491370>>}
global
namespace
globals()
keyword is a dictionary of the global$($module$)$ namespace. You can see the __name__
that you might’ve seen in my program but didn’t exactly know where it comes from! When you execute the file, that file acts like the entry point so its __name__
is default set to __main__
. That’s why there’re if __name__ == '__main__:...
codes out there!
1
globals()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{'__name__': '__main__',
'__doc__': 'Automatically created module for IPython interactive environment',
'__package__': None,
'__loader__': None,
'__spec__': None,
'__builtin__': <module 'builtins' (built-in)>,
'__builtins__': <module 'builtins' (built-in)>,
'_ih': ['', 'globals()'],
'_oh': {},
'_dh': [PosixPath('/Users/jasonlee/Desktop/AI_STUDY/Python')],
'In': ['', 'globals()'],
'Out': {},
'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7fd680491370>>,
'exit': <IPython.core.autocall.ZMQExitAutocall at 0x7fd6804a3a30>,
'quit': <IPython.core.autocall.ZMQExitAutocall at 0x7fd6804a3a30>,
'_': '',
'__': '',
'___': '',
'_i': '',
'_ii': '',
'_iii': '',
'_i1': 'globals()'}
Did you notice something? The builtin
namespace is actually included in the global
namespace!
Modify globals
1
2
globals()['__name__'] = '__modified__'
globals()['__name__']
1
'__modified__'
As you can see, you can actually modify the global namespace
local
namespace
Local namespace is binded to the current namespace that your code is actually in. The local namespace for a function is created when the function is called, and removed when it returns or an execption occurs To retrieve it, use locals()
.
Side Note: if you execute locals()
in the global $($or module$)$ namespace, it does the exact same thing as globals()
1
2
3
4
5
def local_fn():
x = 1
print(locals())
local_fn()
1
{'x': 1}
As you can see, after we declared the variable x
with the value 1, you can see that the local namespace contains only x
. Now, let’s try to modify it.
1
2
3
4
5
6
7
def local_fn():
x = 1
print("Before attempt to modify: ",locals())
locals()['x'] = 99999
print("After attempt to modify: ",locals())
local_fn()
1
2
Before attempt to modify: {'x': 1}
After attempt to modify: {'x': 1}
Notice that even though we tried to assign a new value to the variable x
, the namespace didn’t change!
Scope
A scope is a region where a namespace is directly accessible.
nonlocal x
Within a local namespace, you can only read
the variables found outside the current namespace. If you every try to write
to that variable, it will just create a new local variable
in that innermost scope, unaffecting the outer variable. Below, in inner()
, x is assigned by 999 but for the second print statement, you can see that the x = 1
remains unchanged.
1
2
3
4
5
6
7
8
9
10
def local_fn():
x = 1
def inner():
x = 999
print(x)
inner()
print(x)
local_fn()
1
2
999
1
To rebind the outer-scope variables, you can use nonlocal
keyword followed by the variable name.
1
2
3
4
5
6
7
8
9
def local_fn():
x = 1
def inner():
nonlocal x
x = 999
print(x)
inner()
print(x)
local_fn()
1
2
999
999
nonlocal x
rebinds the outer x’s scope to the inner scope. That’s why if we do print(x)
outside the inner, we can see that the value indeed changed.
global x
Simiarly, you can rebind the variables residing in the global namespace into the local function by using global x
keyword.
1
2
3
4
5
6
7
8
def local_fn():
def inner():
global x
x = 999
inner()
local_fn()
print(x)
1
999
At first glance, it looks very strange that the last print function actually prints x
even if we have never created such one. The reason for that is in the inner()
, we binded the variable x from the global namespace.
vars()
vars()
is a built-in function that returns the __dict__
attributes for a module, class, object, or any other object with a __dict__
attributes.
Notice that some objects such as instances and modules have writable __dict__
dictionary containing the object’s attributes. However, some objects like class
has read only __dict__
to prevent modification. For example, classes use a types.MappingProxyType
to prevent dictionary modifications.
Without any argument, vars()
acts the same as locals()
1
2
3
class Person:
def __init__(self):
pass
1
vars(Person)
1
2
3
4
5
mappingproxy({'__module__': '__main__',
'__init__': <function __main__.Person.__init__(self)>,
'__dict__': <attribute '__dict__' of 'Person' objects>,
'__weakref__': <attribute '__weakref__' of 'Person' objects>,
'__doc__': None})
1
Person.__dict__
1
2
3
4
5
mappingproxy({'__module__': '__main__',
'__init__': <function __main__.Person.__init__(self)>,
'__dict__': <attribute '__dict__' of 'Person' objects>,
'__weakref__': <attribute '__weakref__' of 'Person' objects>,
'__doc__': None})
1
Person.__dict__['__module__'] = "Let me change"
1
2
3
4
5
6
7
8
9
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [13], in <module>
----> 1 Person.__dict__['__module__'] = "Let me change"
TypeError: 'mappingproxy' object does not support item assignment
As you can see, the __dict__
of a class is a types.MappingProxyType which you cannot modify
Namespace and Scope exercise
Below code is referenced from documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def scope_test():
def do_local():
spam = "local spam" # no effect: local
def do_nonlocal():
nonlocal spam # rebind the variable from the enclosing function's scope or the nearest scope.
spam = "nonlocal spam"
def do_global():
global spam # We're dealing with the module namespace! That's why the third print() still says "nonlocal spam"
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam) # out: test spam
do_nonlocal()
print("After nonlocal assignment:", spam) # out: nonlocal spam
do_global()
print("After global assignment:", spam) # out: nonlocal spam
scope_test()
print("In global scope:", spam) # out: global spam
1
2
3
4
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
vars(object)
Return the dict attribute for a module, class, instance, or any other object with a dict attribute.
Objects such as modules and instances have an updateable dict attribute; however, other objects may have write restrictions on their dict attributes $($for example, classes use a types.MappingProxyType to prevent direct dictionary updates$)$.
Without an argument, vars()
acts like locals()
. Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.
A TypeError exception is raised if an object is specified but it doesn’t have a dict attribute (for example, if its class defines the slots attribute).