1. Structuring imports
Now you've got a complete documented package, you need to think about how users will access its different parts.
2. Without package imports
The package you were working on has no internal imports yet - neither does this one.
This means when you import the package, you cannot access any of the subpackages or modules. The package doesn't know about them.
3. Without package imports
To access the subpackages, you would need to import each of them separately, each time you use them.
4. Without package imports
The subpackages don't know about the modules they contain either.
5. Without package imports
So each module has to be imported too.
We can stop this by using internal imports, to import the modules into the subpackages, and the subpackages into the package.
This gives our package structure, and allows us connect its different parts.
6. Importing subpackages into packages
In the package's init-dot-py file, we import the subpackages.
We can do this using absolute or relative imports.
The path of absolute imports starts at the top of the package. Here we tell Python to look within my-sklearn and import the preprocessing subpackage.
Alternatively, we can use a relative import, and start the path from the current file. The dot here means the current file's parent directory. So this relative import says from the current directory import preprocessing.
You only need one of these lines. In Python, absolute imports are preferred, they are more explicit. But you'll see later that these import statements can get really long. That's when we use relative imports.
7. Importing modules
After making this change, we can access the subpackage when we import my-sklearn, but we still can't access its modules.
8. Importing modules
Importing modules is the same as importing subpackages.
Inside the subpackage's init-dot-py file, we add a statement to import the normalize module.
We can use an absolute import, starting from the top of the package, or a relative import starting from this file.
9. Restructuring imports
Now when we import the package, we can access all the functions in this module.
Sometimes this will leave you with a very long path to access a function.
10. Import function into subpackage
You can set up shortcuts to get rid of this. Let's say in the normalize module, there is only one function you want users to access. The other code in the module is just helper functions for this.
In the preprocessing init-dot-py file you can directly import the useful function.
11. Import function into subpackage
Now you've imported the normalize-data function into preprocessing, so you can use this shorter path to access it.
12. Importing between sibling modules
If a module file is getting too big, you might split it into multiple files.
Here some of the functions from normalize have been moved into funcs-dot-py. However, we still need to use them inside the normalize module, so we need to import them.
As usual, we can use absolute or relative imports to import the two functions.
13. Importing between modules far apart
There might be classes or functions you want to use in many of your modules. Here there is a custom exception class which is defined in utils-dot-py.
To import this into these other modules, we can use this absolute import, or this relative import. Previously, we said that one dot in a path meant the parent directory of the file. Two dots means the parent of the parent directory. Starting from normalize-dot-py in the file tree, its parent is preprocessing, and its parent is my-sklearn. Then from the utils file in this directory we import the exception class.
14. Relative import cheat sheet
Here's a cheat sheet you can refer back to for relative imports.
15. Let's practice!
Now let's practice.