HSHimanshu Sharma
Python Notes

Python modules: import styles, aliases, reload, random and __name__

Python modules: import styles, aliases, reload, random and __name__ Advertisement

A module is simply a Python file whose code another file can reuse. The standard library ships hundreds of them (math, random, datetime, json), pip installs thousands more, and every .py file you write is a module too. Learning to import them well is the step that takes you from writing scripts to building programs out of parts. This post covers the import styles, aliases, inspecting a module, reloading it, the random module and the special __name__ variable. Every output below was produced on a real interpreter (Python 3.9).

Why use modules

A module gives you three things. First, reuse: you write a function once and import it everywhere. Second, organisation: a 2,000-line script becomes five files of 400 lines, each about one topic. Third, separate names: a variable called total in one module does not clash with a total in another, because each module has its own namespace.

The four ways to import

Suppose we use the math module:

import math
print(math.sqrt(16), math.pi)                  # 4.0 3.141592653589793

from math import sqrt, pi
print(sqrt(16), pi)                            # 4.0 3.141592653589793

import math as m
print(m.floor(2.7))                            # 2

from math import factorial as fact
print(fact(5))                                 # 120
Style You write Use it when
import math math.sqrt(x) The default. It is always clear where a name comes from.
from math import sqrt sqrt(x) You use one or two names many times.
import math as m m.sqrt(x) The module name is long (import numpy as np is a convention).
from math import * sqrt(x) Almost never. It floods your namespace and hides where names come from.

Module aliasing

import module as alias renames the module in your file only. After import math as m, the name math is no longer defined in your program:

import math as m
try:
    math
except NameError as e:
    print(e)               # name 'math' is not defined

This is a common surprise: the alias replaces the name, it does not add a second one.

Member aliasing

from module import name as other does the same for one member. It is useful when two modules offer the same name, or when the original name is awkward:

from math import sqrt as root
from cmath import sqrt as complex_root
print(root(9), complex_root(-9))        # 3.0 3j

You can import several members in one line, from math import sqrt, ceil, floor, and the brackets let you split a long list over lines.

What is inside a module

Two built-in functions help you explore:

import math
names = [n for n in dir(math) if not n.startswith("_")]
print(len(names) > 40, "sqrt" in names, "gcd" in names)      # True True True
print(math.sqrt.__doc__.splitlines()[0])                      # Return the square root of x.

dir(module) lists every name in the module. help(math.sqrt) prints the documentation in the console. Special attributes tell you more:

print(math.__name__, math.sqrt.__name__)       # math sqrt
import os
print(os.__file__.endswith("os.py"))           # True

module.__file__ shows where the source lives (built-in modules written in C, like math on some systems, have none). Reading the source of a standard-library module is one of the best ways to improve.

Python runs a module once

The first import runs the file from top to bottom and stores the result in a cache called sys.modules. Later imports reuse it. We can prove this with a small module:

# hello.py
print("loading hello")
value = 1
def greet():
    return "hi"
import hello          # prints: loading hello
import hello          # prints nothing: already loaded
import sys
print("hello" in sys.modules)       # True

Running the second import prints nothing, because Python found hello in sys.modules. This is why top-level code in a module (like a connection to a database) runs only once per program.

Reloading a module

If you change hello.py while a program or an interactive session is running, import hello will not pick up the change, because of the cache. To force it, use importlib.reload:

import importlib
import hello
# ... edit hello.py so that value = 2 ...
importlib.reload(hello)      # runs the file again
print(hello.value)           # 2

Reloading is mostly a tool for interactive work and notebooks. It has a catch: objects created from the old version keep the old code, and names imported with from hello import value are not updated. In a normal program, you simply restart it.

The random module

random is the module most beginners meet first, and it shows several import ideas at once.

import random
random.seed(7)                       # makes the results repeatable
print(random.random())               # 0.32383276483316237
print(random.randint(1, 10))         # 3
print(random.choice(["a", "b", "c"]))

The numbers above come from seed(7) on Python 3.9; with a different seed (or none) you get different values, which is the point. Here is the full set you will use:

Function What it does
random.random() a float from 0.0 up to, but not including, 1.0
random.uniform(a, b) a float between a and b
random.randint(a, b) an integer from a to b, both included
random.randrange(a, b, step) like range: the end is excluded
random.choice(seq) one item from a sequence
random.choices(seq, k=3) k items, with repetition
random.sample(seq, k) k different items, without repetition
random.shuffle(list) shuffles a list in place and returns None
import random
random.seed(1)
deck = list(range(1, 6))
random.shuffle(deck)
print(sorted(deck))                         # [1, 2, 3, 4, 5]  (same items, new order)
print(len(random.sample(range(100), 5)))    # 5

Two warnings. The random module is not secure: it must never generate passwords, tokens or anything an attacker could benefit from guessing. For that, use the secrets module. The Password Generator on this site uses the browser's secure generator for the same reason. And never name your own file random.py: Python would import your file instead of the library, and you would get confusing errors.

The special variable __name__

Every module has a built-in variable called __name__. When Python runs a file directly, it sets __name__ to the string "__main__". When another file imports it, __name__ is the module's name. That lets a file work as both a library and a program:

# calc.py
def add(a, b):
    return a + b

print("name is", __name__)

if __name__ == "__main__":
    print(add(2, 3))

Running python3 calc.py printed:

name is __main__
5

Importing it from another file (import calc) printed only name is calc, and the add(2, 3) demo did not run. Put your demo or main() call under this check so that importing the file never starts the program by accident. The packages post shows how __name__ behaves inside a package.

Where Python finds modules

When you write import x, Python looks at the built-in modules first, then the folders listed in sys.path: the folder of the script you ran, the folders in the PYTHONPATH variable, and the folders where Python and pip install libraries. If the module is in none of them, you get:

try:
    import nothere
except ModuleNotFoundError as e:
    print(e)              # No module named 'nothere'

The fixes are, in order of likelihood: check the spelling, run pip install for the package, make sure you run the program from the right folder, and make sure the virtual environment you installed into is the one that is active.

Useful standard modules to know

Module Typical use
math square roots, logarithms, trigonometry, gcd, factorial
random random numbers, shuffling, sampling
datetime dates, times and differences between them
os and pathlib files, folders, environment variables
sys arguments, the path, exiting a program
json reading and writing JSON
re regular expressions
logging log messages
collections Counter, namedtuple, deque

Common mistakes

  • Naming your own file after a library (random.py, json.py, math.py) so it shadows the real one.
  • Using from module import * and not knowing where a name came from.
  • Expecting import x as y to leave x defined.
  • Expecting a second import to re-run an edited file.
  • Using random for security.
  • Putting program start-up code at the top level instead of under if __name__ == "__main__":.

Practice

Create shapes.py with functions area_circle(r) and area_rect(w, h), using math.pi. Add a demo under the __name__ check. Import it from a second file in three different styles, and print the area of a circle with radius 3. Then write a small dice game: roll two dice with random.randint ten times and count how often the total is 7.

Continue

Modules group code in one file; packages group modules in folders. Next, look at functions, the units that modules contain, and see the language fundamentals post for the types you will use. The Python video course covers the same topics step by step, and the Python cheat sheet summarises the import forms.

Advertisement