-
Notifications
You must be signed in to change notification settings - Fork 0
Importing Guide
https://stackoverflow.com/questions/32152373/python-why-can-i-import-modules-without-init-py-at-all
https://www.pythonforthelab.com/blog/complete-guide-to-imports-in-python-absolute-relative-and-more/
Module from standard library can be imported directly using import statement. The reason behind this is because all the path to the module for the standard lib was included in the env PYTHONPATH. We can append new path to **PYTHONPATH ** and python can directly use the module inside of the path using the import keyword directly.
import random
#example use
random.choices(['a','b','c'], k=12)Assigned to variable to local scope:
import random as ran
#example use
ran.choices([a,b,c], k=12)from random import choices
#example use
choices([a,b,c], k=12)from module import *
#example use
choices([a,b,c], k=12)When we use import statement, python will prioritize finding the module within standard lib first, if the name not available inside of standard lib then python file find the file within local scope.
It's always the best we didn't name any of the local python module (python file) same as the builtin module to avoid conflict.
Example same naming local python file threading.py will have conflict with builtin module threading.
If the module bear the same name as the local module we want to call the local instead of the python standard lib module, we can initialized our folder as packages by including file init.py in the folder.
• Standard library
• Current directory
• External module (PYTHONPATH)
import sys
for path in sys.path:
print(path)Module from environment can be imported directly as well after we source the environment. Sourcing the environment will replace the central python installation module with the new environment module path.
Asssuming two python file located within same dir structure on the same level we can import the module directly without any issues.
pythonmodule/
├── onemodule.py
├── __pycache__
│ └── onemodule.cpython-37.pyc
└── twomodule.py
1 directory, 3 files
As the tree structure above the onemodule.py and twomodule.py located in the same dir, so additional setup needed we can directly import the onemodule into twomodule directly, drop the .py when importing the module.
import onemodule
onemodule.function()def function():
print('Hi')Same as the the importing from the central python path, module inside same dir can use statement like 'from' and 'as'
Starting from the python version 3.3 the file** __init__.py** no longer needed to find the module, but it's still needed to declare python folder as packages. So import still can work without the __init__.py
/home/fitri/pythonmodule
├── lower
│ ├── __pycache__
│ │ └── thirdmodule.cpython-37.pyc
│ └── thirdmodule.py
├── onemodule.py
├── __pycache__
│ └── onemodule.cpython-37.pyc
└── twomodule.py
3 directories, 5 files
From the directory structure above, importing thirdmodule inside of the twomodule can be done by calling the module path then module name.
File twomodule.py:
import lower.thirdmodule
lower.thirdmodule.secondfunction()Same as all the other examples, this module import also can be used with statement 'from' and 'as'.
import onemodule
from lower import thirdmodule
onemodule.function()
thirdmodule.secondfunction()import onemodule
from lower import thirdmodule as three
onemodule.function()
three.secondfunction()We can add the any local folder to the PYTHONPATH environment file using the two method:
import os
import sys
sys.path.append(os.getcwd)$ export PYTHONPATH=$PYTHONPATH':/home/user/'
/home/fitri/pythonmodule
├── first
│ └── one.py
├── second
│ └── two.py
└── start.py
2 directories, 3 files
In the first case, we want to import the function inside of two.py into the one.py, if we tried to import directly as we did like the the above example we will get failing error.
def onefunction():
print('THis is one function')from first import one
one.onefunction()$ python two.py
Traceback (most recent call last):
File "second/two.py", line 1, in <module>
from first import one
ModuleNotFoundError: No module named 'first'
The file will return an error, this reason for this is very simple, as dicuss above, python will look for the name first inside standard library first, then it it can't found it, will will look into the current dir and subdirectories.
As the the folder first is not located inside of folder second (but on the same level) thus, it can't found the folder, as it only looking within second dir and subdir under its.
To solve this, we need to specify where this module located and let python know where it can find the module.
As discuss above, there's two way to do this which is including the parents dir to the PYTHONPATH env (recommended) and append it to the env on runtime.
$ export PYTHONPATH=$PYTHONPATH':/home/fitri/pythonmodule'
After we done append and rerun, python will have no problem looking for the folder since it can browser the subdir under the pythomodule dir.
Keypoint here, if we want to use absolute path, we need to use the env PYTHONPATH since python need to find within the dir specified inside of the env for the folder and module.
pythonmodule/
├── first
│ ├── one.py
│ └── __pycache__
│ └── one.cpython-37.pyc
├── second
│ ├── __pycache__
│ │ └── two.cpython-37.pyc
│ └── two.py
└── start.py
4 directories, 5 files
Using the same dir structure, if we attempt to use relative path such as '.' (current dir) and '..' (upper dir) without running the pythol file as packages, we will encounter error.
from ..first import one
one.onefunction()def onefunction():
print('This is one function')$ python two.py
ValueError: attempted relative import beyond top-level package
$ python -m pythonmodule.second.two
It's recommended to use the absolute path with PYTHONPATH env variable as it's much simple and doesn't require the module to be run as package in commandline with python -m.
It's recommend to add every level with __init__.py to treat the folder as packages, so if the folder containing multiple module and we want to import all the module, we can import the package instead of individual module.
.
├── first
│ ├── one.py
│ └── __pycache__
│ └── one.cpython-37.pyc
├── second
│ ├── __init__.py
│ ├── numberone.py
│ ├── numbertwo.py
│ ├── __pycache__
│ │ └── two.cpython-37.pyc
│ └── two.py
└── start.py
4 directories, 8 files
From the dir above, if we want to import folder second as package we can add the __init__.py to initialize this as package then we can import the package itself instead of per module.
import second
second.two.function()