The Python Import System

Python includes an import system that let us:

  • organize large code into small reusable pieces;

  • share code with other people and, conversely, use other people's code.

There are two main concepts in the Python import system: module and package. A module is a Python file (usually ending with .py, sometimes .pyd if it is an compiled module). A package is a folder that contains modules or other packages inside. Despite these definitions, pythonists often use the terms "module" and "package" interchangeably, and there isn't much of a problem with that. Generally speaking, anything that can be imported (we will now see what does that mean) is a module.

The import system let us use variables, functions, classes, exceptions and other objects defined inside a module by means of the from and import keywords.

Let's see an example. Create two files inside the same directory with the names main.py and mymodule.py. Inside the latter we will put some functions and variables:

# mymodule.py
pi = 3.141592
def add(a, b):
    return a + b
def is_even(n):
    return n % 2 == 0

If we want to access an object from this file from our main.py, we must import it via the import keyword, and then make use of one of the objects by prefixing the module name and a dot.

# main.py
import mymodule
result = mymodule.add(7, 5)
print(result)
print(mymodule.pi)

(By convention, all the import lines should always go at the beginning of the file.)

When we import a module, we tell Python that we want to make use of some object within it. In this case, we are using the add() function and the pi variable. We haven't used is_even(), but that's okay. It is not necessary to use all the objects in a module. It is something common to import a module and only use one or a few objects. Note that when saying import mymodule, we do not specify the file extension, thus mymodule could be mymodule.py or mymodule.pyd. Python will import whichever finds first.

The first place Python will look when told to import a module is the local folder or the current working directory. The current working directory is the location from which a program is executed. For example, if we run a Python file from the terminal, the location where the terminal is at the time the file is run is the current working directory. If we execute a file from a code editor (such as Visual Studio Code or PyCharm), the current working directory is usually the same folder where the file is located.

If Python doesn't find the module in the current working directory, it will look at the Lib and Lib/site-packages folders, which are located in the Python installation directory. So any module that lies inside one of these two folders can be imported from any location. If we open the Lib folder, we will already find a large number of modules and packages in there:

/images/the-python-import-system/standard-library.png

The standard library is a set of modules and packages included with every Python installation, which provides solutions to common (and not so common) problems. For example, the statistics standard module has a mean() function to calculate the average of a list of numbers:

>>> import statistics
>>> statistics.mean([1, 3, 7, 10])
5.25

The Lib/site-packages folder stores modules and packages developed by the community (listed in https://pypi.org/) that can be installed via pip, the official language tool for managing third-party packages.

Ways to Import a Module

We have just seen how to import a module using the import keyword. Here's an alternative syntax:

# main.py
from mymodule import add, pi
result = add(7, 5)
print(result)
print(pi)

By using the from ... import ... form, we specifically tell Python which objects we want to import from a particular module. The imported objects are then brought into our file like any other object defined within it. For this reason, it is not necessary (nor even possible) to use the mymodule. prefix.

It is important to know that there is no performance difference between this method and the previous one (import). When we use the import mymodule syntax, we simply tell Python that at some point we will use some object inside mymodule; then the objects will be actually imported when used. Which of the two syntaxes should be used, then? It depends on what is being imported. In most cases it is indifferent, and we can choose the syntax that is most comfortable for us. But sometimes one syntax has better readability than the other. If we have such a line:

import twisted.python.threadpool
tp = twisted.python.threadpool.Threadpool()

To avoid repeating the whole path of modules and packages (twisted.python.threadpool) as a prefix to the Threadpool class, it is probably easier and more comfortable to say:

from twisted.python.threadpool import Threadpool
tp = Threadpool()

However, sometimes using the module name as a prefix improves readability. In such cases we would use import instead. For example, the choice() function within the random standard module randomly picks an element from the list we pass as argument. If we opted for from random import choice, we would use the function like this:

print(choice([1, 2, 3, 4, 5]))

Looking at this line of code, we don't know by what criteria choice() picks an element. Instead, this is quite clear:

print(random.choice([1, 2, 3, 4, 5]))

When faced with a case where neither syntax has obviously a benefit over the other (in terms of readability), it is best to follow the convention found in the examples of the module's official documentation.