10. Files and Modules#

10.1. Creating modules#

All we need to create a module is a text file with a .py extension on the filename:

#  seqtools.py
#
def remove_at(pos, seq):
    return seq[:pos] + seq[pos+1:]

We can now use our module in both programs and the Python shell. To do so, we must first import the module. There are two ways to do this:

>>> from seqtools import remove_at
>>> s = "A string!"
>>> remove_at(4, s)
'A sting!'

and:

>>> import seqtools
>>> s = "A string!"
>>> seqtools.remove_at(4, s)
'A sting!'

In the first example, remove_at is called just like the functions we have seen previously. In the second example the name of the module and a dot (.) are written before the function name.

Notice that in either case we do not include the .py file extension when importing. Python expects the file names of Python modules to end in .py, so the file extention is not included in the import statement.

The use of modules makes it possible to break up very large programs into manageable sized parts, and to keep related parts together.

10.2. Namespaces#

A namespace is a syntactic container which permits the same name to be used in different modules or functions (and as we will see soon, in classes and methods).

Each module determines its own namespace, so we can use the same name in multiple modules without causing an identification problem.

# module1.py

question = "What is the meaning of life, the Universe, and everything?"
answer = 42
# module2.py

question = "What is your quest?"
answer = "To seek the holy grail."

We can now import both modules and access question and answer in each:

>>> import module1
>>> import module2
>>> print(module1.question)
What is the meaning of life, the Universe, and everything?
>>> print(module2.question)
What is your quest?
>>> print(module1.answer)
42
>>> print(module2.answer)
To seek the holy grail.
>>>

If we had used from module1 import * and from module2 import * instead, we would have a naming collision and would not be able to access question and answer from module1.

Functions also have their own namespace:

def f():
    n = 7
    print("printing n inside of f: %d" % (n))

def g():
    n = 42
    print("printing n inside of g: %d" % (n))

n = 11
print("printing n before calling f: %d" % (n))
f()
print("printing n after calling f: %d" % (n))
g()
print("printing n after calling g: %d" % (n))

Running this program produces the following output:

printing n before calling f: 11
printing n inside of f: 7
printing n after calling f: 11
printing n inside of g: 42
printing n after calling g: 11

The three n’s here do not collide since they are each in a different namespace.

Namespaces permit several programmers to work on the same project without having naming collisions.