---
jupytext:
  formats: content_md///md:myst,content///ipynb
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
    jupytext_version: 1.13.8
kernelspec:
  display_name: Python 3 (ipykernel)
  language: python
  name: python3
---

(python:modules-packages)=
# Modules and Packages

We already met modules and packages in the [](python:crash). Here we add the details and learn how to write new modules and packages.

## Importing Modules

To get access to the functionality of a module it has to be imported into the source code file or into the interactive interpreter session:
```python
import module_name
```
This creates a Python object with name `module_name` (everything is an object in Python!) whoes methods are the functions defined on the module file.
All names (functions, types, and so on) defined in the module then can be accessed this way:
```python
module_name.some_function()
```

Use the built-in function `dir` to get a list of all names defined in an imported module.

```{code-cell} ipython3
import datetime
print(dir(datetime))
```

A module's name can appear very often in source code. The `as` keyword allows to abbreviate module names:
```python
import module_name as mod

mod.some_function()
```
It is even possible to avoid typing module names at all. If only few functions of a module are needed, then they can be imported directly:
```python
from module_name import some_function, some_other_function

some_function()
some_other_function()
```
The `as` keyword can be used to abbreviate function names, too:
```python
from module_name import some_function as func

func()
```
To directly import all functions from a module use `*`:
```python
from module_name import *

some_function()
```
But be careful; modules may contain hundreds of functions and importing all these functions may slow down your code.

```{note}
The `import` statement makes the Python interpreter look for a file `module_name.py`. If it cannot find a built-in module with this name (that is, a module integrated directly into the interpreter), then it looks in the directory containing the source code file.
Then several other directories are taken into account. If the interpreter does not find the requested module, an error message is shown.
```

## Importing Packages

Packages are collections of modules and can be imported in the same way as modules.
Packages may contain subpackages. An `import` statement could look like this:
```python
import package_name

package_name.subpackage_name.module_name.some_function()
```

The `import` statement creates a tree of objects and subobjects which reflects the structure of the package.
To import only one subpackage or one module from a package, use `from`:
```python
from package_name import subpackage_name

subpackage_name.module_name.some_function()
```
or
```python
from package_name.subpackage_name import module_name

module_name.some_function()
```

The placeholder `*` and renaming with `as` are available, too.

## The Python Standard Library

Python ships with a large number of modules and packages, known as Python standard library. Have a look at the [complete list](https://docs.python.org/3/library/index.html) of the standard library's contents and also at [Brief Tour of the Standard Library](https://docs.python.org/3/tutorial/stdlib.html) as well as [Brief Tour of the Standard Library - Part II](https://docs.python.org/3/tutorial/stdlib2.html).

We already introduced some of the standard library's modules and packages (`datetime` and `os.path` for instance) and we will continue to introduce new functionality when needed for our purposes.

## Writing New Modules

Writing our own module is very simple: Put function definitions in a file `my_module.py` and import it with `import my_module`.
Writing modules makes code reusable and increases readability.

When importing a module the Python interpreter executes the module file. If you want to use a Python source code file as script as well as as module, you might check the value of the pre-defined variable `__name__`.
If `__name__ == '__main__'`, then the code is being executed as a script. If `__name__ == 'module_name'`, then the code is being run due to an `import` statement.

It's also possible to use [compiled modules](https://docs.python.org/3/tutorial/modules.html#compiled-python-files).

## Writing New Packages

Of course you can write your own packages. A package then is a directory `package_name` which contains the Python files for all modules in the package and in addition a file `__init__.py`. This file might be empty, but is required to mark a directory as Python package. Subpackages are subdirectories with `__init__.py` file.

For details see [Python's documentation](https://docs.python.org/3/tutorial/modules.html#packages).

## Private Members

Python does not support hidden functions or variables in modules. Also hiding members of a class from the user of the class is not possible. But sometimes this would be quite useful. Variables needed only for internal calculations or little helper functions and methods shouldn't be visible from outside, because, if they were hidden, then we could change their name or remove them completely if desired without breaking source code which uses the module or class.

In Python there is a convention to mark private members: a leading underscore like in `_hidden_by_convention`. Variables, functions and methods preceded by an underscore should not be accessed or called from outside the module or class definition. But this is a convention. Nothing prevents you from violating this convention.
