- Покоряем Python — уроки для начинающих
- Python Packages – Creating and Accessing
- How to Create a Python Package?
- What can we keep in a Python Package?
- Can we Create sub-packages in Python?
- Python Package Examples
- 1. Creating a Package
- 2. Adding Modules to the Package
- 3. Importing Modules from a Package
- 4. Import * from a package
- How to add a Package to the System Path
- Conclusion
- References:
Покоряем Python — уроки для начинающих
Если вы решили использовать импортирование пакетов, существует еще одно условие, которое необходимо будет соблюдать: каждый каталог в пути, указанном в инструкции импортирования пакета, должен содержать файл с именем __init__.py, в противном случае операция импорта пакета будет терпеть неудачу. То есть в примере выше каталоги dir1 и dir2 должны содержать файл с именем __init__.py каталог-контейнер dir0 может не содержать такой файл, потому что сам он не указан в инструкции импортирования пакета. Точнее говоря, для такой структуры каталогов:
dir0\dir1\dir2\mod.py
и инструкции импортирования, имеющей следующий вид:
import dir1.dir2.mod
применяются следующие правила:
• dir1 и dir2 должны содержать файл __init__.py .
• dir0 , каталог-контейнер, может не содержать файл __init__.py – этот файл
будет проигнорирован, если он присутствует.
• dir0 , но не dir0\dir1 , должен присутствовать в пути поиска модулей (то есть он должен быть домашним каталогом или присутствовать в переменной окружения PYTHONPATH и так далее).
Таким образом, структура каталогов в этом примере должна иметь следующий вид (здесь отступы указывают на вложенность каталогов):
dir0\ # Каталог-контейнер в пути поиска модулей
dir1\
__init__.py
dir2\
__init__.py
mod.py
Файлы __init__.py могут содержать программный код на языке Python, как любые другие файлы модулей. Отчасти они являются объявлениями для интерпретатора и могут вообще ничего не содержать. Эти файлы, будучи объявлениями, предотвращают неумышленное сокрытие в каталогах с совпадающими именами истинно требуемых модулей, если они отображаются позже в списке путей поиска модулей. Без этого защитного механизма интерпретатор мог бы выбирать каталоги, которые не имеют никакого отношения к вашему программному коду, только лишь потому, что в пути поиска они появляются ранее.
В общем случае файл __init__.py предназначен для выполнения действий по инициализации пакета, создания пространства имен для каталога и реализации поведения инструкций from * (то есть from . import *), когда они используются для импортирования каталогов:
Инициализация пакета
Когда интерпретатор Python импортрирует каталог в первый раз он автоматически запускает программный код файла __init__.py этого каталога. По этой причине обычно в эти файлы помещается программный код, выполняющий действия по инициализации, необходимые для файлов в пакете.
Например, этот файл инициализации в пакете может использоваться для создания файлов с данными, открытия соединения с базой данных и так далее. Обычно файлы __init__.py не предназначены для непосредственного выполнения – они запускаются автоматически, когда выполняется первое обращение к пакету.
Инициализация пространства имен модуля
При импортировании пакетов пути к каталогам в вашем сценарии после завершения операции импортирования превращаются в настоящие иерархии вложенных объектов. Например, в предыдущем примере после завершения операции импортирования можно будет использовать выражение dir1.dir2 , которое возвращает объект модуля, чье пространство имен содержит все имена, определяемые файлом __init__.py из каталога dir2 . Такие файлы создают пространства имен для объектов модулей, соответствующих каталогам, в которых отсутствуют настоящие файлы модулей.
Поведение инструкции from *
В качестве дополнительной особенности, в файлах __init__.py можно использовать списки __all__ , чтобы определить, что будет импортироваться из каталога инструкцией from *. Список __all__ в файлах __init__.py представляет собой список имен субмодулей, которые должны импортироваться, когда в инструкции from * указывается имя пакета (каталога). Если список __all__ отсутствует, инструкция from * не будет автоматически загружать субмодули, вложенные в каталог, – она загрузит только имена,
определяемые инструкциями присваивания в файле __init__.py , включая любые субмодули, явно импортируемые программным кодом в этом файле. Например, инструкция from submodule import X в файле __init__.py создаст имя X в пространстве имен каталога. (Мы поближе познакомимся со списком __all__ в следующих постах.)
Эти файлы можно оставить пустыми, если вам не требуется выполнять специальных действий. Однако для успешного выполнения операции импортирования каталогов они должны существовать обязательно.
Эти файлы можно оставить пустыми, если вам не требуется выполнять специальных действий. Однако для успешного выполнения операции импортирования каталогов они должны существовать обязательно.
Python Packages – Creating and Accessing
Python packages help us to manage modules and python scripts. They are normal directories with a init script – __init__.py.
How to Create a Python Package?
We can create a package by following below steps.
- Create the package directory – we can use terminal or Python IDE for this.
- Create __init__.py file – this is required to convert a normal directory into python package. This file is used to initialize the package and list all the modules. In the simplest form, this file can be empty.
What can we keep in a Python Package?
- The initialization file
- Python modules
- Python scripts
- Any other type of files
So in general, a package just like is a directory in our computer systems. The only difference is the mandatory inclusion of the __init__.py file.
Can we Create sub-packages in Python?
Yes, we can create a package inside another package. We have to follow the packaging rules to create a sub-package too.
Python Package Examples
Let’s look into some examples of creating and using packages.
1. Creating a Package
$ mkdir utilities $ touch utilities/__init__.py $ mkdir utilities/strings $ mkdir utilities/strings/__init__.py $ tree . └── utilities ├── __init__.py └── strings └── __init__.py 3 directories, 1 file $
2. Adding Modules to the Package
Let’s say we have two python modules – math.py and str_utils.py. They have few functions that will be used in our program.
def add(x, y): return x + y def multiply(x, y): return x * y
str_utils.py:
def to_uppercase(s): s = str(s) return s.upper() def reverse(s): s = str(s) return s[::-1]
We want to add these modules to our packages. Just copy these files to the packages directory where you want to keep these modules.
$ ls math.py str_utils.py utilities $ mv math.py utilities $ mv str_utils.py utilities/strings $ tree . └── utilities ├── __init__.py ├── math.py └── strings ├── __init__.py └── str_utils.py 3 directories, 3 files $
3. Importing Modules from a Package
The syntax to import a python module inside a package is:
import package.sub_package1.sub_package2.module import package.sub_package1.sub_package2.module as module
Python uses sys.path variable to search for packages and modules. The current directory is part of the sys.path variable. So we will keep our python script in the python-packages directory. Otherwise, we will have to add the package location in the sys.path variable.
$ cat my_script.py import sys print(sys.path) $ python3.7 my_script.py ['/Users/pankaj/Desktop/python-packages', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages'] $
Here is the my_script.py code to access the modules from the packages and calling their functions.
import utilities.math as math import utilities.strings.str_utils as str_utils print(math.add(10, 20)) print(str_utils.reverse("ABC"))
We can also import a module using below syntax:
from package.sub_package1.sub_package2 import module
Here is the updated example to access “math” and “str_utils” module in our program.
from utilities import math from utilities.strings import str_utils print(math.add(10, 20)) print(str_utils.reverse("ABC"))
4. Import * from a package
We can import every module from a package using the following syntax.
from package.sub_package1.sub_package2 import *
In this case, Python searches sub_package2 for packages, modules, and functions. This can produce side effects by importing something that you don’t want to. Also, it’s a very time taking process.
We can define a list of modules to be imported by creating __all__ variable in the __init__.py file.
utilities/__init__.py:
print('utilities package initialized') __all__ = ['math']
utilities/strings/__init__.py:
print('utilities.strings package initialized') __all__ = ['str_utils']
The updated my_script.py code is:
from utilities import * from utilities.strings import * print(math.add(10, 20)) print(str_utils.reverse("ABC"))
$ python3.7 my_script.py utilities package initialized utilities.strings package initialized 30 CBA
Notice that the python code in the __init__.py gets executed first when the packages are initialized and imported.
How to add a Package to the System Path
It’s not feasible to always depend on the directory hierarchy to import package modules. We can add our custom package to the sys.path variable and then import them in any script.
import sys sys.path.append("/Users/pankaj/Desktop/python-packages") print(sys.path) import utilities.math as math print(math.add(1, 2))
$ python3.7 my_script.py ['/Users/pankaj', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python37.zip', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages', '/Users/pankaj/Desktop/python-packages'] utilities package initialized 3 $
Conclusion
Packages in Python allow us to divide our application modules and scripts into logical modules. This keeps our code base clean and easy to maintain.