In this section, we’ll cover some of the tools you need as your scripts get to be bigger than just the contents of a single file. Namely code organization, command-line arguments and file I/O.
Inside a single python module (file) there are multiple namespaces. The global namespace represents the full contents of the file, while inside each function there is a local namespace. The contents of these namespaces can be accessed as dictionaries using the functions globals()
and locals()
respectively.
When objects (variables, functions, etc) are defined in the file, they manipulate the global namespace. Anything defined inside a function manipulates its local namespace. Notice in the example below that the namespace is manipulated as the file is read. In other words, the first print statement occurs before the interpreter is aware of the presence of the function definition.
Note | |
---|---|
The following example makes use of |
organization-1-namespaces.py.
'''Some documentation for this file.''' import pprint print 'globals before def: %s\n' % pprint.pformat(globals(), indent=4) def simple(): print 'locals before a: %s\n' % locals() a = 'simple' print 'locals after a: %s\n' % locals() return a print 'globals after def: %s\n' % pprint.pformat(globals(), indent=4) simple()
$ python organization-1-namespaces.py globals before def: { '__builtins__': <module '__builtin__' (built-in)>, '__doc__': 'Some documentation for this file.', '__file__': 'samples/organization-1-namespaces.py', '__name__': '__main__', '__package__': None, 'pprint': <module 'pprint' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pprint.pyc'>} globals after def: { '__builtins__': <module '__builtin__' (built-in)>, '__doc__': 'Some documentation for this file.', '__file__': 'samples/organization-1-namespaces.py', '__name__': '__main__', '__package__': None, 'pprint': <module 'pprint' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pprint.pyc'>, 'simple': <function simple at 0x100425f50>} locals before a: {} locals after a: {'a': 'simple'}
Have another look at an example similar to the one above. Notice that the modules that are imported are present in the global namespace.
organization-2-imports.py.
import collections import pprint d = collections.deque() d.append('a') d.appendleft('b') pprint.pprint(globals())
$ python organization-2-imports.py {'__builtins__': <module '__builtin__' (built-in)>, '__doc__': None, '__file__': 'samples/organization-2-imports.py', '__name__': '__main__', '__package__': None, 'collections': <module 'collections' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/collections.pyc'>, 'd': deque(['b', 'a']), 'pprint': <module 'pprint' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/pprint.pyc'>}
Objects from this module are accessed using dotted notation.
Alternatively, you can import the specific element from the module, using the from ... import
syntax.
organization-3-import-submodule.py.
from collections import deque from pprint import pprint d = deque() d.append('a') d.appendleft('b') pprint(globals())
$ python organization-3-import-submodule.py {'__builtins__': <module '__builtin__' (built-in)>, '__doc__': None, '__file__': 'samples/organization-3-import-submodule.py', '__name__': '__main__', '__package__': None, 'd': deque(['b', 'a']), 'deque': <type 'collections.deque'>, 'pprint': <function pprint at 0x100435578>}
It is also possible to import an entire namespace. This should be done with caution, as it can lead to unexpected elements in your namespace and conflicts in naming.
organization-4-import-all.py.
from collections import * from pprint import pprint d = deque() d.append('a') d.appendleft('b') pprint(globals())
$ python organization-4-import-all.py {'Callable': <class '_abcoll.Callable'>, 'Container': <class '_abcoll.Container'>, 'Hashable': <class '_abcoll.Hashable'>, 'ItemsView': <class '_abcoll.ItemsView'>, 'Iterable': <class '_abcoll.Iterable'>, 'Iterator': <class '_abcoll.Iterator'>, 'KeysView': <class '_abcoll.KeysView'>, 'Mapping': <class '_abcoll.Mapping'>, 'MappingView': <class '_abcoll.MappingView'>, 'MutableMapping': <class '_abcoll.MutableMapping'>, 'MutableSequence': <class '_abcoll.MutableSequence'>, 'MutableSet': <class '_abcoll.MutableSet'>, 'Sequence': <class '_abcoll.Sequence'>, 'Set': <class '_abcoll.Set'>, 'Sized': <class '_abcoll.Sized'>, 'ValuesView': <class '_abcoll.ValuesView'>, '__builtins__': <module '__builtin__' (built-in)>, '__doc__': None, '__file__': 'samples/organization-4-import-all.py', '__name__': '__main__', '__package__': None, 'd': deque(['b', 'a']), 'defaultdict': <type 'collections.defaultdict'>, 'deque': <type 'collections.deque'>, 'namedtuple': <function namedtuple at 0x100425ed8>, 'pprint': <function pprint at 0x1004355f0>}
Once your code starts to get bigger than a script, you will want to start organizing it into modules. Unlike some other languages (Java for example) each file in Python is a module. Directories can also be used as a further layer of organization with some care.
Using the file-only model, functions can be created in another file in the same directory (or somewhere in the $PYTHONPATH) and imported using the filename and the function name.
tools.py.
def shorten(toolong): return toolong[:2]
complexity-4-file-module.py.
from tools import shorten print shorten('abcdef')
$ python complexity-4-file-module.py ab
As code starts to require even more organization, perhaps with multiple types of utility functions, this file could be moved to a subdirectory. In order to use a directory as a module, it is required that the special file __init__.py
be present in the directory, which can be empty.
$ ls tools2 tools2/__init__.py tools2/strings.py
tools2/strings.py.
def shorten(toolong): return toolong[:2]
complexity-5-directory-module.py.
from tools2 import strings print strings.shorten('abcdef')
$ python complexity-5-directory-module.py ab