там, где они впервые используются? Есть, что почитать на эту тему? (сам я строго следую заветам Гвидо — импортирую все строго в начале файла)
В смысле использовать локальные импорты внутри функций?
паттерн factory и производные от него - зачем вам тянуть дерево зависимостей модулей (а может еще и инициализацию оных) в паять если вы не будете это использовать
Вот есть реальный юзкейс, где импорт модулей настолько долгий?
Есть только один сценарий, когда это может быть оправдано. Чтобы избежать проблемы циклических импортов, если невозможно устранить циклические зависимости между модулями.
речь не только про долгое, импорт может закончится и неудачей, если не стоят какие-то доп. вещи в системе в моменте инициализации модуля
Самое главное — избегание ошибок импортов в рантайме. Я вот щас открыл исходники OpenShot, и тут тоже импортируют аж на 183 строке. Глазам больно
Вообще есть, но это довольно специфическая ситуация и уже скорее относится к низкоуровневым оптимизациям. Софт, который запускается по требованию и должен запускаться быстро. Например некоторые увесистые CLI или какие-нибудь лямбды.
А при чем здесь ошибки импорта? Ошибки импорта ты обрабатываешь там же где импортируешь модуль, если предполагается что этот модуль опциональный.
Это обычно рядом с остальными импортами обрабатывается. Импорт заворачивается в try-except ImportError, и в случае ошибки импортируется заглушка или какой-нибудь флаг отсутствия модуля выставляется
за такие модули, которые выполняют логику в момент импорта нужно бить по рукам и гнать вон из профессии.
Не, допустим, я импортирую что-то в середине скрипта. При запуске полскрипта отработает, а на импорте ImportError. Если бы импорт был сразу, скрипт даже не запустился бы — я про это
Если бы импорт был сразу, то ты точно так же мог бы обработать ошибку импорта в месте импорта
Некрасиво это :/
Нет, это вполне распространенная практика.
Распространенная, но... некрасивая
А гонять импорты на каждый вызов функции стало быть красивая?
это может быть сделано намеряно. я так делаю для unstable фичей, чтобы в проде не дай бог (без спец выставления переменных среды) не включили - fail fast
Обычно такие условные импорты прячут за фасад пакета
я немного о другом. например модуль во время импорта загружает датасет или еще какую-нибудь хрень творит.
ну малоли что он творит - например модуль будет использовать zlib в 100% случаев. Что б сразу не проверить что zlib есть в системе?
А вот модуль должен вообще датасеты грузить? Мож в модуле функцию или метод init() написать, которую и заворачивать в try/except, а не сам импорт?
Красивее, чем импорты внутри функций, ошибки которых вообще никак не обрабатываются
> Мож в модуле функцию или метод init() написать, которую и заворачивать в try/except, а не сам импорт? звучит как хрень. какую проблему это "заворачивание" должно решать?
так, тут уже у меня вопрос, ты про такое говорил? так у меня выглядит файл init.py https://pastebin.com/zv8WV0Ph
не совсем, но у твоего кода другая проблема.
Если модуль делает что-то тяжёлое, да ещё и упасть при этом может, предлагается обернуть его импорт в try/except. Но зачем обрабатывать импорт, когда в модуле можно вынести это что-то тяжёлое в какую-нибудь функцию, и в вызывающем коде отлавливать эксепшены уже в ней
ты про engine, base и session?
ключевое здесь "если". если модуль делает что-то тяжелое в момент импорта и нет возможности его изменить, то это проблема, которую нужно решать. в остальных случаях это не должно становиться практикой по-умолчанию.
конкретно про engine который зависит от глобальной конфигурации, которая грузится в момент импорта.
Ну значит, я правильно мыслю
то есть, его надо обернуть в функцию, к примеру: get_engine(db_url): return create_engine(db_url)
и какой в этом смысл?
тоже над этим думаю не совсем понимаю как исправить
1. конфигурацию следует загружать например в точке входа в твое приложение. 2. на основе конфигурации создавать engine 3. sessionmaker можно создать глобально и связать его с engine в момент вызова, а можно создавать там же где и engine.
Обсуждают сегодня