Overview
This article provides an easier-to-understand summary of all the content in Chapter 6. Modules of the official Python v3.13 Tutorial.
1. Why Use Modules?
When you write code directly in the interpreter, and then exit and restart it, all the definitions (functions and variables) are lost. Therefore, for longer code, it's better to write the code in a file and have the interpreter execute that file. This method is called a script.
If your code gets even longer, you might want to split it into several files for easier maintenance. And you'll want to import functions from one file into another without having to copy and paste them every time.
This is made possible by Python's module. If you put all your definitions in a file called a module, you can import them into other modules or the main module.
2. Basic Concepts of Modules
The module name is the filename without the
.py extension. It is also available in the global variable __name__ within the module. For example, if you save the following code in your current directory as fibo.py in your IDE:# Fibonacci numbers module def fib(n): """Write Fibonacci series up to n.""" a, b = 0, 1 while a < n: print(a, end=' ') a, b = b, a+b print() def fib2(n): """Return Fibonacci series up to n.""" result = [] a, b = 0, 1 while a < n: result.append(a) a, b = b, a+b return result
You can import the
fibo module in the interpreter using import.>>> import fibo
However, this does not directly bring the names within the fibo module into the current namespace. It only adds the module object named
fibo, and you need to use the . to access the names inside it.>>> fibo.fib(1000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 >>> fibo.fib2(100) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>> fibo.__name__ 'fibo'
If you assign it to a local name, you can use it without the
..>>> fib = fibo.fib >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
3. Advanced Concepts of Modules
3.1. Various import Methods
3.1.1. from
When importing a module, you might want to bring the names from within the module directly into the current namespace. If you find it tedious to call them as
modname.itemname, you can use from as shown below.>>> from fibo import fib, fib2 >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
When you import this way, the name
fibo is not brought into the local namespace.Alternatively, you can use
* to import all names from a module at once.>>> from fibo import * >>> fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Names starting with
_ are not imported. Using * is not recommended because you don't know which names are being imported, which can lead to unintended consequences by overwriting names in the current namespace. It's best used in interactive shells where typing everything out is tedious.3.1.2. as
Using
as during import immediately assigns the module to the name following as. This is useful for shortening long module names. Otherwise, it works the same.>>> import fibo as fib >>> fib.fib(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
Of course, you can also use it with
from.>>> from fibo import fib as fibonacci >>> fibonacci(500) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
3.2. Executing Modules as Scripts
Writing as a script means executing a .py file from the terminal.
When you run a module like
fibo from the terminal as shown below, it gets executed just like when it's imported. The difference is that __name__ is set to “__main__”.$ python fibo.py <arguments>
So, if you add the following code to the bottom of your module:
if __name__ == "__main__": import sys fib(int(sys.argv[1]))
You can make the file usable as both a module and a script.
For example, running it from the terminal as below sets
__name__ to “__main__”, so fib() is executed:$ python fibo.py 50 0 1 1 2 3 5 8 13 21 34
But if you import it as a module,
__name__ is still “fibo”, so the code is not executed.>>> import fibo >>>
This is useful when you need to add a user interface to a module or run it for debugging purposes.
3.3. Module Execution Location and Timing
You will have defined functions, declared variables, etc., in your module. Let's say they are in the module's global namespace. When you import the module, the statements in the module are executed only once at the import statement. And those names are placed in that module's namespace. Therefore, there is no conflict between the names in your current code and the names in the module's code.
Therefore, if you import a module inside a function or class, the module's scope is limited to that function or class. Thus, it is generally good practice to put all import statements at the top of your code. This makes the module available in the global scope, so you can call it from anywhere in your code.
Also, since the statements in a module are executed only once upon import, any changes you make to the module will not be reflected immediately. This is because if a module has thousands of lines of code, re-executing it on every import would significantly degrade performance. So, it is only executed on the first import. To be precise, when importing, Python checks if the module to be imported is in
sys.modules. If not, it executes the module and then adds it to sys.modules. If it is already there, it skips execution. If you want to reflect changes to a module, you can either restart the interpreter or use importlib.reload(). Like this:import importlib importlib.reload(modulename)
A point to note here is that only the module name can be reloaded. So if you imported using
from, the module name will not be in the current namespace. Therefore, you need to import the module without from, reload it, and then import the names from the module again using from.import importlib import fibo importlib.reload(fibo) from fibo import fib
3.4. The Module Search Path
When a module is imported, how does Python find the file that contains it?
Let's say you import a module named
spam. The interpreter first searches for a built-in module in sys.builtin_module_names. If not found, it searches for spam.py in the list of directories given by sys.path. sys.path is initialized in the following order:- The directory containing the input script.
PYTHONPATH(a list of directory names, with the same syntax as the shell variablePATH).
- The installation-dependent default (where external packages are installed, e.g., by pip).
There is one thing to be careful about here. After the initialization of
sys.path is complete, this list can be modified while the code is running. As mentioned above, the directory containing the script is at the top of sys.path, so it has a higher priority than the standard library (libraries made by others that are commonly used). So, if a module with the same name exists in the current directory, it can cause unintended errors.3.5. “Compiled” Python files
To speed up loading modules, Python caches the compiled version of each module in the
__pycache__ directory as module.version.pyc, where the version encodes the format of the compiled file; it generally contains the Python version number. For example, in CPython release 3.13 the compiled version of spam.py would be cached as __pycache__/spam.cpython-313.pyc.Python automatically checks the modification date of the source file against the compiled version and recompiles if the compiled version is out-of-date. The compiled module is platform-independent, so it can be shared with other systems.
Python does not check the cache in two circumstances.
- It always recompiles and does not store the result for the module that’s loaded directly from the command line.
- It doesn’t check the cache if there is no source module. To support a non-source (compiled only) distribution, the compiled module must be in the source directory and there must not be a source module.
Here are some more advanced tips:
- You can reduce the size of a compiled module by using the
-Oor-OOswitches on the Python command. The-Oswitch removesassertstatements, the-OOswitch removes bothassertstatements and__doc__strings.
- A program doesn’t run any faster when it is read from a
.pycfile than when it is read from a.pyfile; the only thing that’s faster about.pycfiles is the speed with which they are loaded.
- The
compileallmodule can create.pycfiles for all modules in a directory.
4. Standard Modules
Python comes with a library of standard modules, described in a separate document, the Python Library Reference (“Library Reference” hereafter). Some modules are built into the interpreter; these provide access to operations that are not part of the core of the language but are nevertheless built in, either for efficiency or to provide access to operating system primitives, such as system calls. The set of such modules is a configuration option which also depends on the underlying platform. For example,
winreg is only provided on Windows systems. One particular module deserves some attention: sys, which is built into every Python interpreter.For example, when the interpreter is in interactive mode,
sys.ps1 and sys.ps2 define the strings used as primary and secondary prompts:>>> import sys >>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print('Yuck!') Yuck! C>
The variable
sys.path is a list of strings that determines the interpreter’s search path for modules. It can be modified as shown below:import sys sys.path.append('/ufs/guido/lib/python')
5. The dir() Function
The built-in function
dir() is used to find out which names a module defines. It returns a sorted list of strings:>>> import fibo, sys >>> dir(fibo) ['__name__', 'fib', 'fib2'] >>> dir(sys) ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework', '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook', 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info', 'warnoptions']
Without arguments,
dir() lists the names you have defined currently:>>> a = [1, 2, 3, 4, 5] >>> import fibo >>> fib = fibo.fib >>> dir() ['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
Note that it lists all types of names: variables, modules, functions, etc.
dir() does not list the names of built-in functions and variables. If you want a list of those, they are defined in the standard module builtins:>>> import builtins >>> dir(builtins) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
6. Packages
6.1. Basic Concepts of Packages
Packages are a way of structuring Python’s module namespace by using “dotted module names”. For example, the module name
A.B designates a submodule named B in a package named A.Just like modules, packages use the
. to separate their namespaces, so you don't have to worry about global variable names clashing.Let's take a more concrete example. Suppose you are creating a package for handling various sound files and sound data. First, you need to manage various formats like
.wav, .aiff, and .au. You also need modules for applying effects like echo and equalizer to the sound data. These modules will continue to be added. For example, the file structure can become complex like this:sound/ Top-level package __init__.py Initialize the sound package formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py ... filters/ Subpackage for filters __init__.py equalizer.py vocoder.py karaoke.py ...
When importing such a package, Python searches through the directories on
sys.path looking for the package subdirectory.In the example above, you can see
__init__.py in each package. This file is required to make Python treat the directories as containing packages. This is to prevent directories with a common name, such as string, from unintentionally hiding valid modules that appear later on the module search path. __init__.py can be empty, or it can execute initialization code for the package.6.2. Importing Packages
If you want to import a specific module from a package, you can do it like this. This imports the submodule named
sound.effects.echo. You must use the full name when using it.import sound.effects.echo sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
Alternatively, you can import it like this to use it without the package prefix.
from sound.effects import echo echo.echofilter(input, output, delay=0.7, atten=4)
Another way is to import the function or variable directly, like this:
from sound.effects.echo import echofilter echofilter(input, output, delay=0.7, atten=4)
That is, when using the
from package import item format, item can be a submodule, a subpackage, or a name within it like a function, class, or variable. The principle here is that it checks if the item after import is defined in the package. If not, it assumes item is a module and tries to load it. If it fails, an ImportError is raised.Conversely, in a format like
import item.subitem.subsubitem, the last item, subsubitem, can be a module or a package, but it cannot be a name defined in subitem. Of course, the preceding items, item and subitem, must be packages.6.3. Importing * From a Package
What happens when a user of a package imports using
from sound.effects import *? One might expect that it would automatically import all the submodule.py files in the package, but that's not the case. Doing so would take a long time to import all the submodules and could lead to unexpected side effects.Therefore, the author of the package can provide an explicit index. This is done by defining a list called
__all__ in the package's __init__.py. Here, you can list all the module names that should be imported when a from package import * statement is encountered. If the author thinks this is not useful, they can choose not to define it.Let's look at an example. If you put the following code in
sound/effects/__init__.py, only three submodules will be imported when you do from sound.effects import *.__all__ = ["echo", "surround", "reverse"]
A point to note here is that a submodule can be shadowed by a local name defined in
__init__.py. In the example below, since there is a local function named reverse, the reverse submodule will not be imported, and the function will be called instead.__all__ = [ "echo", # refers to the 'echo.py' file "surround", # refers to the 'surround.py' file "reverse", # !!! refers to the 'reverse' function now !!! ] def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule return msg[::-1] # in the case of a 'from sound.effects import *'
If
__all__ is not defined, from sound.effects import * does not import all submodules from sound.effects. It only imports the names defined in __init__.py.Of course, things that are explicitly specified are imported correctly. In the code below, the
echo and surround submodules are imported correctly.import sound.effects.echo import sound.effects.surround from sound.effects import *
Therefore, using
import * in production code is a bad habit. It is better to import by explicitly specifying the names.6.4. Intra-package References
When you have a subpackage structure, we have been looking at absolute imports so far. For example, if the
sound.filters.vocoder submodule needs the sound.effects.echo module, you would import it using from sound.effects import echo.Python also supports relative imports. Let's look at the example below.
from . import echo from .. import formats from ..filters import equalizer
Let's say this code is defined in the
sound.effects.surround module. A single . in the from statement means the package where the current module is located. .. means the parent package. So, ..filters can find the filters module of the parent package, sound.One thing to be careful about is that relative imports are based on the name of the current module's package. Since the main module does not have a package, you must always use absolute imports in that case.
6.5. Packages in Multiple Directories
Before the code in
__init__.py is executed, a package contains a list of strings called __path__ which contains the directory of that package. You can modify this value in __init__.py, which affects the search for subpackages and modules, allowing you to add packages from multiple paths.Reference
[1] Python Software Foundation. "6. Modules" The Python Tutorial, version 3.13, Python Software Foundation, 2024, https://docs.python.org/3.13/tutorial/modules Accessed 26 July 2025.
