Skip to content

Python Modules & the Standard Library

In software development, a library is like a toolbox for developers. Instead of implementing every part of your code from scratch, a library gives you pre-written, reusable code, such as functions, classes, and data structures, that you can use in your projects. In Python, each file of such code is called a module.

Python comes with an extensive standard library: a large collection of built-in modules. They are standardized, well-vetted solutions to many of the problems and tasks you will face daily as a programmer, such as:

  • Interacting with the operating system
  • Working with files
  • Networking
  • Working with date and time
  • Performing mathematical operations
  • Using regular expressions
  • Testing and debugging your code
  • And much more

Some of the most popular modules:

ModulePurpose
mathHelpful functions for more complex mathematical operations
randomGenerating random numbers and making random choices
reWorking with regular expressions
datetimeWorking with dates and times

No installation is needed. You only have to import a module to use it.

TaskSyntaxExample
Import a moduleimport moduleimport math
Use its contentsmodule.namemath.sqrt(36)
Give it an aliasimport module as aliasimport math as m
Import specific namesfrom module import a, bfrom math import sin, cos
Alias a specific namefrom module import a as xfrom math import sqrt as root
Import everything (avoid)from module import *from math import *
Explore a moduledir(module), help(module)help(math.sqrt)
Run code only when executed directlyif __name__ == '__main__':See the idiom

Use an import statement to access the variables, constants, functions, and classes defined in a module. Import statements are generally written at the top of the file.

import_syntax.py
import module_name

For example, to import the math module:

import_math.py
import math

Then call a function from the module with dot notation: the module name, a dot, then the name.

dot_notation.py
import math
print(math.sqrt(36)) # 6.0

Here sqrt is an abbreviation of “square root”. Inside the parentheses you pass any necessary arguments. In this case, the number you want the square root of.

To import a module under a different name, add as followed by the alias at the end of the statement.

import_alias_syntax.py
import module_name as module_alias

Aliases are often used to shorten long module names or to avoid naming conflicts.

import_alias.py
import math as m
print(m.sqrt(36)) # 6.0, access elements through the alias

Sometimes you do not need everything from a module, only one or two functions or classes. In that case, start the statement with from, name the module, then import the names you want.

from_import_syntax.py
from module_name import name1, name2

You can then use those names without the module prefix. To give them aliases, use as after each name:

from_import_alias_syntax.py
from module_name import name1 as alias1, name2 as alias2

For example, to import only the radians, sin, and cos functions from math:

from_import_math.py
from math import radians, sin, cos

Now you can call these functions directly, without math as a prefix.

To find the sine and cosine of an angle given in degrees, convert it to radians with radians(), then pass the result to sin() and cos():

sine_and_cosine.py
from math import radians, sin, cos
angle_degrees = 40
angle_radians = radians(angle_degrees)
sine_value = sin(angle_radians)
cos_value = cos(angle_radians)
print(sine_value) # 0.6427876096865393
print(cos_value) # 0.766044443118978

Notice that the functions are called directly, without the name of the module as a prefix. That is a consequence of importing them with this alternative syntax.

This style is convenient, but it can cause naming conflicts if your script already defines a function or variable with the same name. The later definition silently replaces the earlier one.

name_conflict.py
from math import sqrt
def sqrt(x): # Replaces the imported sqrt
return 'my own version'
print(sqrt(36)) # 'my own version'

An alias avoids the clash:

avoid_conflict.py
from math import sqrt as math_sqrt
def sqrt(x):
return 'my own version'
print(math_sqrt(36)) # 6.0
print(sqrt(36)) # 'my own version'

An import ending with an asterisk tells Python to import everything from the module, with no module prefix needed.

wildcard_import.py
from module_name import *

For example, after importing math this way, you can call any function defined in it without the prefix:

wildcard_math.py
from math import *
print(sqrt(36)) # 6.0
print(pow(5, 2)) # 25.0
print(exp(1)) # 2.718281828459045
import math
math.sqrt(36)
math.pi
  • Every use shows where the name comes from
  • No naming conflicts
  • Slightly longer to type

The safest default.


Import statements work exactly the same for functions, classes, constants, variables, and any other element defined in a module.

import_constant.py
import math
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045

Here is a class from the datetime module. It creates a date object that represents July 15, 1959, assigns it to a variable, and accesses the day, month, and year individually with dot notation:

import_class.py
import datetime
birthday = datetime.date(1959, 7, 15)
print(birthday.day) # 15
print(birthday.month) # 7
print(birthday.year) # 1959

The same thing with from:

from_import_class.py
from datetime import date
birthday = date(1959, 7, 15)
print(birthday) # 1959-07-15

You can find more information about a module’s content in the official Python documentation for that module. You can also explore from inside Python:

exploring_modules.py
import math
print('sqrt' in dir(math)) # True, dir() lists every name in the module
print(math.__name__) # 'math'
help(math.sqrt) # Prints the documentation for sqrt

ModuleUse it for
mathSquare roots, trigonometry, logarithms, constants
randomRandom numbers, shuffling, sampling
datetimeDates, times, differences between dates
reRegular expressions (pattern matching in text)
os, pathlibOperating system interaction, file paths
sysThe interpreter: command-line arguments, exiting, module paths
json, csvReading and writing common data formats
collectionsCounter, defaultdict, deque
itertools, functoolsAdvanced iteration and function tools
statisticsMean, median, standard deviation
timePausing, measuring elapsed time
loggingRecording diagnostic messages
unittestWriting automated tests
urllib, http, socketNetworking
sqlite3A lightweight built-in database
argparseCommand-line interfaces
dataclasses, enum, typingStructuring and annotating your code
math_examples.py
import math
print(math.sqrt(36)) # 6.0
print(math.ceil(3.2)) # 4, round up
print(math.floor(3.7)) # 3, round down
print(math.gcd(12, 18)) # 6, greatest common divisor
print(math.factorial(5)) # 120
print(math.hypot(3, 4)) # 5.0, length of the hypotenuse
print(math.isclose(0.1 + 0.2, 0.3)) # True, safe float comparison
random_examples.py
import random
print(random.random()) # A float from 0.0 up to (not including) 1.0
print(random.randint(1, 6)) # An integer from 1 to 6, both ends included
print(random.choice(['red', 'green', 'blue'])) # One random item
cards = [1, 2, 3, 4, 5]
random.shuffle(cards) # Shuffles the list in place
print(random.sample(cards, 2)) # Two unique items, as a new list
random.seed(42) # Same seed gives the same sequence (reproducible runs)
datetime_examples.py
from datetime import date, datetime, timedelta
birthday = date(1959, 7, 15)
print(birthday.strftime('%B %d, %Y')) # July 15, 1959
print(birthday.strftime('%A')) # Wednesday
print(date(2024, 1, 31) + timedelta(days=1)) # 2024-02-01
print((date(2025, 1, 1) - date(2024, 1, 1)).days) # 366
parsed = datetime.strptime('2024-03-15', '%Y-%m-%d')
print(parsed) # 2024-03-15 00:00:00
print(datetime.now()) # The current date and time
re_examples.py
import re
print(re.findall(r'\d+', 'a1b22c333')) # ['1', '22', '333']
print(re.sub(r'\s+', ' ', 'a b c')) # 'a b c'
match = re.search(r'(\w+)@(\w+)\.com', 'Write to ann@site.com today')
print(match.group(1)) # 'ann'
print(match.group(2)) # 'site'
files_and_system.py
from pathlib import Path
import os
import sys
path = Path('data') / 'report.txt' # Builds a path with the right separator
print(path.suffix) # '.txt'
print(path.exists()) # True or False
print(os.getcwd()) # The current working directory
print(os.path.join('data', 'x.txt')) # 'data/x.txt' (or 'data\\x.txt' on Windows)
print(sys.version) # The Python version
print(sys.argv) # Command-line arguments as a list of strings
more_modules.py
import json
import statistics
import time
text = json.dumps({'name': 'Ann', 'age': 31})
print(text) # '{"name": "Ann", "age": 31}'
print(json.loads(text)['name']) # 'Ann'
print(statistics.mean([1, 2, 3, 4])) # 2.5
print(statistics.median([1, 3, 2])) # 2
start = time.perf_counter()
time.sleep(0.1) # Pause for a tenth of a second
print(time.perf_counter() - start) # Elapsed seconds, about 0.1

Any Python file is a module. Its name is the filename without .py.

shapes.py
PI = 3.14159
def circle_area(radius):
return PI * radius ** 2
main.py
import shapes
from shapes import circle_area
print(shapes.PI) # 3.14159
print(circle_area(2)) # 12.56636

Both files must be in the same folder (or the folder must be on Python’s search path).

A package is a folder of modules. Adding an __init__.py file marks the folder as a package (it can be empty).

Project layout
project/
├── main.py
└── utils/
├── __init__.py
├── text.py
└── numbers.py
main.py
from utils.text import slugify # A name from utils/text.py
import utils.numbers as nums # The whole module, with an alias
import os.path # The standard library has packages too
from os import path # Same module, imported differently

Inside a package, modules can import their siblings with relative imports:

utils/text.py
from . import numbers # The sibling module numbers.py
from .numbers import clamp # A name from that sibling

When you write import something, Python looks for it in this order:

  1. The module cache. If the module was already imported, Python reuses it from sys.modules.

  2. Built-in modules. Modules compiled into Python itself, such as sys.

  3. The search path (sys.path). A list of folders checked in order: the folder of the running script, any folders in the PYTHONPATH environment variable, the standard library, and installed third-party packages (site-packages).

search_path.py
import sys
for folder in sys.path:
print(folder) # The first entry is the folder of your script

The code in a module executes the first time it is imported. Later imports reuse the loaded module without running it again.

counter_module.py
print('counter_module is loading')
VALUE = 1
import_once.py
import sys
import counter_module # Prints: counter_module is loading
import counter_module # Prints nothing, already loaded
print('counter_module' in sys.modules) # True

To force a re-run during development, use importlib.reload(counter_module).

Do Not Name Your File Like a Standard Module

Section titled “Do Not Name Your File Like a Standard Module”

Because Python searches your script’s folder first, a file called random.py or math.py hides the real module.

random.py (your own file)
import random
print(random.randint(1, 6))
# AttributeError: partially initialized module 'random' has no attribute 'randint'
# (most likely due to a circular import)

Rename your file (for example dice.py) and delete any leftover __pycache__ folder.


Beyond the standard library, thousands of packages written by the community live on the Python Package Index (PyPI). Install them with pip, then import them like any other module.

Terminal
python -m pip install requests
python -m pip list
third_party.py
import requests
response = requests.get('https://example.com')
print(response.status_code)

Now that you know more about modules, there is one very important idiom in Python scripts that is closely related:

main_idiom.py
if __name__ == '__main__':
# Code
pass

__name__ is a special built-in variable in Python.

  • When a Python file is executed directly, Python sets __name__ to the string "__main__".
  • When the file is imported as a module into another script, __name__ is set to the name of that module (usually the filename without the .py extension).
How the file is usedValue of __name__
python greeter.py'__main__'
import greeter from another file'greeter'
python -m greeter'__main__'

That is why you will often find this conditional in Python scripts. It contains the code you want to run only if the script is running as the main program. If the script is imported as a module, the code inside the block does not run.

greeter.py
def greet(name):
return f'Hello, {name}!'
print('greeter: __name__ is', __name__)
if __name__ == '__main__':
print(greet('Ann'))
$ python greeter.py
greeter: __name__ is __main__
Hello, Ann!

The main block runs.

This allows Python scripts to have two purposes: they can be run directly to execute their main logic, or they can be imported into another module without executing that main logic.

A common convention is to put the program’s logic in a main() function and call it from the guard.

app.py
def main():
name = input('Name: ')
print(f'Hello, {name}!')
if __name__ == '__main__':
main()

This keeps the top level tidy and lets tests import and call main() or other functions in the file without side effects.


PEP 8, Python’s style guide, recommends:

  • Put imports at the top of the file, after any module docstring.
  • Group them in this order, with a blank line between groups: standard library, third-party packages, then your own modules.
  • Keep each group alphabetical.
  • Use one import per line (but several names in a from import are fine).
  • Prefer absolute imports to relative ones outside of packages.
import_order.py
import json
import os
from datetime import date
import requests
from myapp.utils import slugify

MistakeProblemFix
import math then sqrt(36)NameError: name 'sqrt' is not definedmath.sqrt(36) or from math import sqrt
from math import sqrt then math.sqrt(36)NameError: name 'math' is not definedsqrt(36), or import math
import math as m then math.piNameError, only the alias existsm.pi
math.sqroot(4)AttributeError: module 'math' has no attribute 'sqroot'Check the spelling with dir(math)
import numpyyModuleNotFoundError: No module named 'numpyy'Fix the name, or pip install the package
from math import fooImportError: cannot import name 'foo' from 'math'The module does not define that name
from module import *Namespace collisions, even replacing built-insImport explicit names
A file named random.py or math.pyHides the standard moduleUse a different filename
Installing with pip for the wrong PythonModuleNotFoundError anywayUse python -m pip install ...
Expecting a second import to re-run a moduleModules load onceimportlib.reload(module)
Two modules importing each otherCircular import errorsMove shared code into a third module
Top-level code with no __main__ guardIt runs on import, causing side effectsWrap it in if __name__ == '__main__':
  1. Use the standard library before writing your own solution or installing a package.
  2. Put all imports at the top of the file, grouped as standard library, third-party, then local.
  3. Prefer import module or explicit from module import name over wildcard imports.
  4. Use aliases to shorten long names or resolve conflicts, and follow community conventions such as np and pd.
  5. Never name your own files after standard library modules.
  6. Use help(), dir(), and the official documentation to explore a module.
  7. Guard script entry points with if __name__ == '__main__': so the file can be both run and imported.
  8. Install third-party packages into a virtual environment with python -m pip.