Модули в Python — это файлы и каталоги, содержащие код, который можно использовать в других программах. Они позволяют организовывать код, делая его более структурированным и повторно используемым. Модули могут содержать функции, классы и переменные.
Как правило, вам потребуется устанавливать модули с помощью команды pip install <имя модуля>
. Однако, установка некоторых модулей может не потребоваться, так как они включены в стандартную библиотеку Python.
Для импорта библиотек используются ключевые слова from
и import
.
Например, давайте импортируем math
и напечатаем число пи:
import math
print(math.pi) # 3.141592653589793
Также можно сделать по-другому:
from math import pi
print(pi)
В первом примере мы импортировали весь модуль math
, а во втором только pi
.
При импорте модуля можно переименовать его, например, если название слишком длинное, а мы хотим обращаться к нему по более короткому имени.
Для этого существует оператор as
, который присваивает новое имя:
from math import pi as p
Также стоит уделить внимание тому, что различные функции могут находиться на разном уровне вложенности:
from sqlalchemy.ext.declarative import declarative_base
В этом случае в модуле sqlalchemy
находится папка ext
, в которой находится файл declarative.py
, в котором находится функция eclarative_base
давайте создадим несколько файлов, чтобы получилась такая структура:
├── example2.py
└── example.py
И создадим в файле example2.py
функцию hello:
def hello(name):
print(f"Hello, {name}")
Чтобы использовать эту функцию в example.py
нужно ее импортировать. Сделать это можно несколькими способами, как описывалось ранее:
# 1 способ
import example2
example2.hello("Someone")
# 2 способ
from example2 import hello
hello("Someone")
можно также присвоить этим модулям другое имя с помощью as
Каталог может восприниматься как модуль. Его можно импортировать как обычный файл, но с некоторыми особенностями. Давайте создадим такую структуру:
├── example.py
└── folder
├── example2.py
└── \__init__.py
Содержание файла example2.py
остается тем же. Теперь давайте воспользуемся функцией hello
:
import folder.example2
folder.example2.hello("Someone")
# 2 способ
from folder.example2 import hello
hello("Someone")
# 3 способ
from folder import example2
example2.hello("Someone")
# 4 способ
import folder
folder.example2.hello("Someone")
Все работает как ожидалось.
__init__.py
Этот файл служит для того, чтобы управлять тем, что будет импортироваться при импорте каталога. Например, так выглядит файл utils/__init__.py
:
from utils.async_timed import async_timed
from utils.delay import delay
from utils.fetch_status import fetch_status
при такой структуре:
.
├── main.py
└── utils
├── __init__.py
├── async_timed.py
├── delay.py
└── fetch_status.py
В файлах каталога utils
содержатся функции, имена которых аналогична этим файлам. Без файла __init__.py
, пришлось бы импортировать и использовать эти модули так:
from utils import async_timed, delay, fetch_status
async_timed.async_timed()
delay.delay()
fetch_status.fetch_status()
Или более удобный вариант:
from utils.async_timed import async_timed
from utils.delay import delay
from utils.fetch_status import fetch_status
async_timed()
delay()
fetch_status()
Но это все не так удобно как вариант ниже:
from utils import async_timed, delay, fetch_status
async_timed()
delay()
fetch_status()
И это все благодаря файлу __init__.py
. Все, что мы сделали, это перенесли эти некрасивые многословные импорты в этот файл и теперь импорт из utils
стал намного проще. Когда нужно выполнить импорт всего один раз, преимущества небольшие, но представьте, насколько был бы удобен импорт, когда нам нужно пользоваться utils
в десятках файлов.
__init__.py
Этот файл позволяет менять внутреннюю структуру каталогов и файлов, не переделывая импорты по всей программе в десятках файлов, а просто изменить импорты в файле __init__.py
.
Например, я захотел сделать вот так:
.
├── main.py
└── utils
├── __init__.py
├── a
│ └── b
│ └── c
│ └── delay.py
├── async_timed.py
└── fetch_status.py
Если бы не файл __init__.py
, то нам бы пришлось менять from utils.delay import delay
на from utils.a.b.c.delay import delay
. Ладно в одном файле, а если в нескольких. Но благодаря __init__.py
можно изменить только его вот так:
from utils.async_timed import async_timed
from utils.a.b.c.delay import delay
from utils.fetch_status import fetch_status
А все импорты utils
в других файлах остались прежними. Удобно!
import *
и файл __init__.py
Файл __init__.py
может быть как и пустым, так и содержать в себе некоторую информацию. Например, он может содержать информацию о том, какие модули импортируются при использовании import *
.
В файле __init__.py
можно определить список __all__
, который определяет импортируемые модули при использовании import *
Давайте это проверим. Для этого создадим каталог и несколько файлов, чтобы получилось вот так:
.
├── example.py
└── folder
├── a.py
├── b.py
├── c.py
└── \__init__.py
__init__.py
:
__all__ = ['a', 'b']
a.py
:
def a_function():
print("a")
b.py
:
def b_function():
print("b")
c.py
:
def c_function():
print("c")
example.py
:
from folder import *
a.a_function()
b.b_function()
c.c_function()
При выполнении example.py
вывод такой:
a
b
Traceback (most recent call last):
File "/.../example.py", line 5, in <module>
c.c_function()
^
NameError: name 'c' is not defined
Как видите, модуль c
не импортировался так как я не включил его в __all__
в файле __init__.py
__init__.py
- самый обычный Python файлПод этим я имею ввиду то, что вы можете помещать в него абсолютно любой код Python и он будет работать как в самом обычном файле. Допустим, мы добавили в __init__.py
новую функцию say_hello()
. Обратиться к ней можно будет по имени каталога, в котором находится __init__.py
. Если взять примеры выше, то это будет utils
, а получить из него say_hello()
можно так: from utils import say hello
. И так с любыми объектами в __init__.py
.
Допустим, у нас есть такая структура:
├── folders
│ ├── folder
│ │ ├── a.py
│ │ └── __init__.py
│ └── folder2
│ ├── example.py
│ └── __init__.py
└── main.py
Как и файла a.py
обратиться к example
? Вот так:
from ..folder2 import example
теперь в example.py
добавим функцию hello
:
def hello(name):
print(f"Hello, {name}")
а в файле a.py
вызовем эту функцию:
def hello_world():
example.hello("World")
Затем в файле main.py
импортируем функцию hello_world
:
from folders.folder.a import hello_world
hello_world()
Запустив все это командой python main.py
, мы получим следующее:
Hello, World
Таким образом, у нас получилась цепочка импорта: folders.folder2.example
-> folders.folder.a
-> main
.
Круговой импорт в Python - это ситуация, когда два или более модуля ссылаются друг на друга при импорте. Это может привести к ошибкам и непредсказуемому поведению программы.
Для примера, давайте создадим такую структуру файлов
.
├── file.py
└── main.py
Теперь в файле file.py
напишем следующее:
from main import name
def hello():
print(f'hello, {name}')
А в main.py
это:
from file import hello
name = "John"
hello()
Запустив этот код, мы получаем ошибку
Traceback (most recent call last):
File "...\main.py", line 1, in <module>
from file import hello
File "...\file.py", line 1, in <module>
from main import name
File "...\main.py", line 1, in <module>
from file import hello
ImportError: cannot import name 'hello' from partially initialized module 'file' (most likely due to a circular import) (...\file.py)
Ошибка говорит о том что нельзя импортировать hello
из частично инициализированного модуля file
. Это как раз таки круговой импорт.
Когда Python выполняет инструкцию import
, он выполняет следующие шаги:
1. Загрузка модуля: Python ищет модуль в кэше (в sys.modules
). Если модуль не найден, он загружает его из файла.
2. Инициализация модуля: При загрузке модуля интерпретатор выполняет его код, создавая пространство имен для этого модуля. На этом этапе все функции и классы становятся доступными, но не все из них могут быть выполнены, пока не будет завершена инициализация.
3. Обработка зависимостей: Если модуль A импортирует модуль B, Python начинает загружать B. Если B также пытается импортировать A, возникает круговая зависимость.
Таким образом, нужно следить, чтобы модули не импортировали друг друга.
Мы разобрались, как импортировать модули, как управлять импортом с помощью файла __init__.py
и разобрали проблему кругового импорта.
Сохраняйте сайт в закладки чтобы узнавать больше нового про Python.
Объектно-ориентированное программирование - одна из самых распространенных парадигм. Знание ООП позволит сделать код более гибким и масштабируемым
В Python 3.10 был добавлен новый функционал - сопоставление с шаблонами с помощью ключевых слов match и case. В статье также рассматривается производительность match/case по сравнению с if/else.
В этой статье описано, что означают различные классы исключений. Также рассмотрено создание собственных классов исключений.
Обработка исключений — это важная часть программирования на языке Python, которая позволяет программе продолжать выполнение даже в случае возникновения ошибок. В этой статье мы рассмотрим основные принципы и методы обработки исключений, а также узнаем, почему они так важны для создания надежных и стабильных программ.