2025, Oct 21 10:16
Можно ли в Python импортировать модуль и имя вместе
Можно ли в Python одновременно импортировать модуль и отдельное имя? Разбираем на примере dataclasses и json: синтаксис import/from и гайд по структуре импорта
При смешении стилей импорта в Python часто возникает соблазн одновременно использовать и import module, и from module import name для одной и той же библиотеки. Мотив обычно один — ясность: вызывать json.dumps и dataclasses.asdict с префиксом модуля, чтобы избежать неоднозначности, а декоратор @dataclass оставить коротким и легко читаемым. Возникает вопрос: допускает ли Python подтягивание и самого модуля, и конкретного символа из него в одной строке?
Пример, иллюстрирующий компромисс
import dataclasses
from dataclasses import dataclass
import json
@dataclass
class Vector3:
    i: int
    j: int
    k: int
    def as_json(self) -> str:
        return json.dumps(dataclasses.asdict(self))
Здесь json.dumps и dataclasses.asdict вызываются с явной квалификацией, тогда как @dataclass используется напрямую — так читается лучше и очевидно, что он относится к модулю dataclasses.
Что на самом деле позволяет язык
Короткий и однозначный ответ: в Python нет единого оператора, который одновременно импортирует и модуль целиком, и символ из этого же модуля. Пару строк нельзя заменить чем-то вроде гипотетического from dataclasses import self, dataclass. Ваша текущая форма соответствует синтаксису оператора import и является правильной.
нет, согласно разделу The import statement - Python Language Reference. То, что у вас уже есть, — корректно.
Практичный обходной путь, если очень нужен один пункт импорта
Если всё же хочется иметь по одной строке импорта на модуль-поставщик, можно вынести импорты в отдельный модуль, а затем импортировать из него. Это не меняет синтаксис Python; дублирование просто перемещается в одно место.
Сначала создайте модуль-агрегатор импортов:
# Содержимое `hub_imports.py`
import dataclasses
from dataclasses import dataclass
import json
Затем используйте их в своём коде:
from hub_imports import dataclasses, dataclass, json
@dataclass
class Node3D:
    a: int
    b: int
    c: int
    def to_json_text(self) -> str:
        return json.dumps(dataclasses.asdict(self))
print(Node3D(a=1, b=2, c=3).to_json_text())
Такой подход оставляет в каждом потребляющем модуле всего один оператор import, при этом вы сохраняете явную квалификацию модуля там, где это добавляет ясности.
Почему это имеет значение
Имена вроде dataclass не всегда уникальны для одной библиотеки; например, альтернативная реализация есть в Pydantic. Осознанный выбор — что импортировать напрямую, а что вызывать через префикс модуля — упрощает аудит и понимание кода. Централизация разрешённых импортов в одном месте также даёт очень явный контроль над тем, что допустимо по всему проекту.
Есть и тонкость, о которой стоит помнить: в dataclasses функция называется asdict(), а не as_dict(). Правильное имя API помогает избежать лишних ошибок во время выполнения.
Подход с централизацией по смыслу напоминает то, что в некоторых JavaScript-кодовых базах называют «barrel files». Это может быть полезно, но остаётся дизайнерским решением, которое нравится не всем. Рассматривайте его как возможный инструмент, а не правило по умолчанию.
Итоги
В Python нет однострочного способа импортировать и модуль, и конкретный символ из него. Идиоматично и правильно — использовать два отдельных оператора import. Если хотите унифицировать импорты по проекту или сократить повторение в отдельных модулях, сгруппируйте их в выделенном модуле и импортируйте оттуда. Сохраняйте явную квалификацию модуля для потенциально неоднозначных вызовов, отдавайте предпочтение ясности для декораторов и часто используемых имён и убеждайтесь, что вызываете корректные API, например dataclasses.asdict().
Статья основана на вопросе с StackOverflow от Dominik Kaszewski и ответе от simon.