Python Fundamentals Tutorial: Code Organization

9. Code Organization

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.

9.1. Namespaces

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.


The following example makes use of import, which will be explained in the next section. It also uses pprint.pformat which converts a dictionary into a string in a manner that is more easily read when printed. 

'''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)


$ python
globals before def: {   '__builtins__': <module '__builtin__' (built-in)>,
    '__doc__': 'Some documentation for this file.',
    '__file__': 'samples/',
    '__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/',
    '__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'}

9.2. Importing modules

Have another look at an example similar to the one above. Notice that the modules that are imported are present in the global namespace. 

import collections
import pprint

d = collections.deque()


$ python
{'__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'samples/',
 '__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. 

from collections import deque
from pprint import pprint

d = deque()


$ python
{'__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__file__': 'samples/',
 '__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. 

from collections import *
from pprint import pprint

d = deque()


$ python
{'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/',
 '__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>}

9.3. Creating Modules

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. 

def shorten(toolong):
    return toolong[:2] 

from tools import shorten

print shorten('abcdef')

$ python

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 be present in the directory, which can be empty.

$ ls tools2


def shorten(toolong):
    return toolong[:2] 

from tools2 import strings

print strings.shorten('abcdef')

$ python

Table of Contents

1. Getting Started
1.1. The Interactive Interpreter
1.2. Lab
1.3. Lab
2. Types
2.1. Strings
2.2. Integers
2.3. Floats
2.4. Complex
3. Variables
3.1. Definining
3.2. Dynamic Typing
3.3. Strong Typing
3.4. Internals
4. Simple Expressions
4.1. Boolean Evaluation
4.2. Truthiness
4.3. Branching (if / elif / else)
4.4. Block Structure and Whitespace
4.5. Lab
4.6. Multiple Cases
4.7. Lab
5. Advanced Types: Containers
5.1. Lists
5.2. Lab
5.3. Strings Revisited
5.4. Tuples
5.5. Lab
5.6. Dictionaries
5.7. Lab
5.8. Sets
5.9. Collection Transitions
6. A Bit More Iteration
6.1. Loop-Else
7. Functions
7.1. Defining
7.2. Arguments
7.3. Mutable Arguments and Binding of Default Values
7.4. Accepting Variable Arguments
7.5. Unpacking Argument Lists
7.6. Scope
7.7. Lab
8. Exceptions
8.1. Basic Error Handling
9. Code Organization
9.1. Namespaces
9.2. Importing modules
9.3. Creating Modules
10. Working with Files
10.1. File I/O
11. Interacting with the Outside World
11.1. Options
12. Regular Expressions (re)
12.1. Lab
13. Functional Programming
13.1. Functions as Objects
13.2. Higher-Order Functions
13.3. Sorting: An Example of Higher-Order Functions
13.4. Anonymous Functions
13.5. Nested Functions
13.6. Closures
13.7. Lexical Scoping
13.8. Useful Function Objects: operator
13.9. Lab
13.10. Decorators
13.11. Lab
14. Advanced Iteration
14.1. List Comprehensions
14.2. Generator Expressions
14.3. Generator Functions
14.4. Iteration Helpers: itertools
14.5. Lab
15. Debugging Tools
15.1. logging
15.2. pprint
15.3. Lab
16. Object-Oriented Programming
16.1. Classes
16.2. Emulation
16.3. classmethod and staticmethod
16.4. Lab
16.5. Inheritance
16.6. Lab
16.7. Encapsulation
16.8. Lab
17. Easter Eggs