You've already learned that it is not convenient write longer programs in the Python interpreter and you've been writing your Python scripts as text files with the .py extension.

The scripts can be easily edited and executed repeatedly. This works nicely up to the point when it becomes too limiting to hold all our code in a single file (e.g., the script becomes too long, parts of code repeat in different scripts).

Can we organize our code better than that?

Modules

Python allows us to organize code in modules. A module is something like a box containing some ready-to-use code. We can pull it from a shelf, import it, and then use it in our script.

For example, you can import the function sqrt from the module math:

from math import sqrt

print(sqrt(2))

In this case, the module math (Python standard library) contains a set of various mathematical functions and constants. With the from <module> import <names> command we pulled from the math modules one function sqrt, which refers to the function calculating square root, and made it available in our program.

Alternatively, you can import a whole module and access its names through the module name and period .. For example:

import math

print(math.cos(math.pi))

... or:

import turtle

turtle.left(90)
turtle.color('red')
turtle.forward(100)
turtle.exitonclick()

Packages

Python allows a special kind of module which itself contains sub-modules. A module which is a collection of modules is called a package in the Python jargon. A package can have sub-packages and, in more complex projects, it is common to have several levels of sub-modules.

Do not fear! Import of a sub-module from a package does not differ from the regular top-level module. The sub-modules are separated by dots, but apart from that, you work with them the same way:

import os       # os is a package
import os.path  # path is submodule of os package, os.path is a full module name

directory = "./test"
if not os.path.exists(directory):
    os.mkdir(directory)

Custom modules

You can also create your own module, simply, by creating a Python file. Functions and variables (and other named objects) that you create there will be available in programs where you import this module.

Let's try it. First, create a new Python file meadow.py and write:

meadow_colour = 'green'
number_of_kitties = 28

def description():
    return 'The meadow is {colour}. There are {number} kitties.'.format(
        colour=meadow_colour, number=number_of_kitties)

And then write in another file write.py with the following content:

import meadow

print(meadow.description())

and run:

$ python3 write.py

Python searches for the imported modules in a defined following order:

  • built-in modules from the Python Standard Library (e.g. sys, math)
  • modules in a directory specified by sys.path, which by default is the same folder where the executed script is located (not the current working directory - where Python command was launched)
  • directories in the PYTHONPATH environment variable
  • the rest of the modules in Python’s standard library (not built-ins) - (e.g. random, os) That is why in 4th lesson with turtle, we said to NOT name the current script turtle.py

Do not forget to have both files (meadow.py and write.py) in the same directory.

Import mechanics and undesired side-effects

What exactly does the command import meadow do?

First, Python looks for a matching file (meadow.py) and runs all the commands in the file, from top to bottom, like it was a regular script. Once it is done, all the names in the global scope (variables, functions, etc.) are remembered and made available for use outside of the module.

When you try to import the same module again, the commands in the module are not executed and Python re-uses the already initialized module.

Try it! Write in the end of meadow.py:

print('The meadow is green!')

And then run python in the command line (if you already have an interactive Python open, close it, and run again) and enter:

>>> import meadow
The meadow is green!
>>> import meadow
>>> import meadow
>>>

The message we print at the end of the module appears only once.

When the module is "doing something" (it prints something, asks the user, writes something into a file) we say that it has a side effect. We generally try to avoid writing modules with side effects. The purpose of a module is to give us functions, that we will use to do something, not to do it instead of us. E.g., when we write import turtle, no window opens. It opens only when we write turtle.forward().

So you had better delete the print from our module.

One directory for every project

From now on, we will work on bigger projects that contain more files. We recommend that you create a folder for each of them.

The import best practice

Python imports are case-sensitive. import Spam is different from import spam.

Where to put the imports?

Always keep imports at the top of your script before you the start of your own code.

Does the order of the imports matter?

Generally, the order of the imports does not matter. though, we often order the imports,

1) modules from the Python system library (e.g., math) 2) third-party libraries (installed with the pip command) 3) imports from our own modules

If you decide to import multiple names from the module do it in one import command, e.g.:

from math import pi, sin, cos

Further reading

You can find more info about import and modules here.