# All About Importing Modules and from Packages

### Module?

A module is just a Python file with the corresponding `.py` extension. So if you're talking about the math module then there is a corresponding `math.py` file that contains functions, classes, and constants that are meant to be used by other Python files.

### Where does Python look for modules

If you have written a python module under say `a_module.py` in a directory of `code`.

And you have a script called `a_script.py` in directory called `scripts`. You would like to use the `a_module` in `a_script.py` by importing it.

```
import a_module
```

Then you try to run the `a_script.py` by running `python3 scripts/a_script.py` it will fail with

```
$ python3 scripts/a_script.py
Traceback (most recent call last):
  File "scripts/a_script.py", line 1, in <module>
    import a_module
ModuleNotFoundError: No module named 'a_module'
```

When Python imports a module it will try to find a package or module. But where does it look? Python has a simple algorithm for finding a module with a given name. It will look for a file called `a_module.py` in the directories listed in the variable `sys.path`.

```
>>> import sys
>>> type(sys.path)
<class 'list'>
>>> for path in sys.path:
...     print(path)
... 
/Users/brettmz-admin/dev_trees/psych-214-fall-2016/sphinxext
/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python37.zip
/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7
/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload
/Users/brettmz-admin/Library/Python/3.7/lib/python/site-packages
/Users/brettmz-admin/dev_trees/grin
/Users/brettmz-admin/dev_trees/rmdex
/usr/local/lib/python3.7/site-packages
```

It doesn't search recursively, it will only search in the directory that is listed under `sys.path`. And as you can see the `code` directory is not in `sys.path` which is why Python could not import `a_module.py`.

To fix this you can just simply append to the `sys.path` list like so:

```
import sys
sys.path.append('code')

import a_module
```

Now this will work as expected. This simple search algorithm for module also works for packages, it searches for packages then the module the same way.

<p class="callout info">Information from: [https://bic-berkeley.github.io/psych-214-fall-2016/sys\_path.html](https://bic-berkeley.github.io/psych-214-fall-2016/sys_path.html) </p>

### What is Namespace package and Regular Package

A namespace packages are special packages that allows you to unify two packages with the same name but are at different directories:

```
path1
+--namespace
   +--module1.py
   +--module2.py
path2
+--namespace
   +--module3.py
   +--module4.py
```

Notice that in order to make Namespace package work you would have to add the two paths `path1` and `path2` to `sys.path`. Then you can import the four modules by doing

```
from namespace import module1
from namespace import module2
from namespace import module3
from namespace import module4
```

Or import specific functions from the module

```
from namespace.module1 import boo
```

Namespace packages basically unifies the two packages with the same name in a single namespace. You can import all four modules freely.

However, if either one of the `namespace` packages gain an `__init__.py` then it will become a normal package, and the unification is no longer as the other directory will be ignored.

If both have `__init__.py` the first one encountered in `sys.path` is the one being used.

##### Regular package

A regular package is a collection of modules. In order to make Python recognize that it is a regular package you must add `__init__.py`. Without `__init__.py` then it will be interpreted as a namespace package which doesn't fit 99% of normal use cases.

So the moral of the story is that if you're creating packages, just put `__init__.py` in it unless you have the special use case of needing to unify two namespace packages that are in different directory.

Regular packages are also searched in `sys.path` just like everything else.