Русский
Русский
English
Статистика
Реклама

Import or from import, that is the question

Есть три стадии знаний: ты используешь инструмент, ты понимаешь как он работает, ты можешь учить других работать этим инструментом. Потихонечку начал перетекать в третью и стал задавать себе вопросы, которые раньше не задавал.


Например, что лучше: import module или from module import function?


Я решил разобраться в этом чуть поглубже, ответы на StackOverflow меня не удовлетворили.


Для тех, кому лень читать: все варианты хороши.


Советы от создателей языка


Обратимся к первоисточникам, а именно к PEP8


Когда импортируете класс из модуля, будет нормально сделать это так:


from myclass import MyClassfrom foo.bar.yourclass import YourClass

Если это вызывает локальный конфликт имён, то можно сделать это явно:


import myclassimport foo.bar.yourclass

И использовать как myclass.MyClass и foo.bar.yourclass.YourClass
PEP-8 поддерживает оба подхода и даёт некоторые рекомендации.


Кто принимает решение?


Тот, кто пишет модуль. Обычно модули пишутся без оглядки на конкретный способ импорта и можно использовать любой подход. Но в целом это вопрос дизайна модуля, поэтому у его автора могут быть конкретные рекомендации и модуль может быть написан с прицелом на конкретный вариант импорта.


Документация


Самый очевидный способ продемонстрировать как пользоваться библиотекой, документация. Не ту документацию, которую никто не читает, а примеры использования.


"Фляжка" и "бутылка" идут по пути точечных импортов.


from flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world():    return 'Hello, World!

from bottle import route, run, template@route('/hello/<name>')def index(name):    return template('<b>Hello {{name}}</b>!', name=name)run(host='localhost', port=8080)

Пайтест выбирает импортирование модуля.


import pytestdef test_zero_division():    with pytest.raises(ZeroDivisionError):        1 / 0

В случае пайтеста это вполне логичный выбор, так как эта библиотека должна быть максимально совместима со всем кодом на планете.
У неё один из самых высоких шансов получить локальный конфликт имён.
Есть даже плагин для линтера который проверяет, что импорты оформлены правильно.


Имена атрибутов модуля


Второй подход основан на выборе имён внутри модуля. Для очень абстрактных имён, например как в некоторых модулях стандартной библиотеки лучше использовать импорт из модуля.


import jsonjson.load(...)json.loads(...)json.dump(...)json.dumps(...)

Без импорта модуля имена теряют контекст и могут внести путаницу.


from pickle import loadfrom marshal import dumpsfrom xmlrpc.client import loadsfrom xml.etree.ElementTree import dump

load без контекста может быть как json.load так, и pickle.load.
При этом вторая функция имеет ограничения по применению в связи безопасностью и ей при просмотре нужно уделить особое внимание. Обратный случай когда имена модуля и его содержимого очень большие и загромождают код. Короткие, абстрактные имена это прерогатива создателей стандартной библиотеки языка. Для своего же кода я выбираю имена среднего и большого размера, которые понятны без контекста в виде имени модуля. Но граничные случаи редки, и большинство библиотек не вызывают проблем при использовании любого из подходов.


Секция импортов


Если импортировать атрибуты из модуля, то секция импортов начинает пухнуть. А если через модуль, то пухнет код.


Секция импортов это та часть кода, которая хорошо поддаётся оптимизации.
Например, некоторые IDE умеет её сворачивать, а так же самостоятельно форматировать. Да и импорты я редко прописываю руками, подсказки по коду предлагают это сделать за меня. Еще можно форматировать импорты сторонними инструментами, например isort.


Лично для меня некоторое многословие в импортах менее страшно чем многословие в коде.


Простота чтения


При импорте отдельных объектов получатся более короткий код. Его проще читать. Меньше переносов строк.


В целом чуда не случается, но читать приятнее.


Рефакторинг


В IDE поддерживаются оба случая на одном уровне, и автоматика работает одинаково. Но иногда бывают сбои: мерджи с другим кодом, ручные переименования/перемещения файлов. Если переименовали объект, а использования забыли, то при импортировании атрибутов код упадёт сразу,
а при доступе через единый модуль только в момент вызова.


Если у вас 100% покрытие тестами разницы нет. Если нет, то второй случай пропустить легко.


MonkeyPatch


При написании тестов порой надо подменить какие-то методы. Вот тут с импортами из модуля начинается цирк. К моменту, когда накладывается патч, ссылка на объект уже имеется в тех местах, где он импортирован, и патчить нужно не место, где объект объявлен, а все места, где был сделан импорт.
Несложно, но немного запарно, и есть шанс что-то поломать при рефакторинге.


Этот момент достаточно частый источник недоумения.


Производительность и память


Бытует миф, что импортирование из модуля только части классов/функций экономит память. На деле в обоих случаях в память загружается модуль целиком, и разницы в производительности нет.


Пространство имён


Если в пространстве имён есть конфликты, то Питон позволяет их обойти двумя способами. Либо import module, либо from module import item as module_item. Мне подход с модулем больше нравится, as практически не использую, пусть лучше будет чуть больше кода с именами модулей, чем добавление новых имён. Хотя есть и устоявшиеся традиции.


import matplotlib.pyplot as pltimport numpy as npimport pandas as pd

Единообразие


На мой взгляд, использование обоих подходов не сильно нарушает единообразие, и можно их спокойно смешивать. Желательно, правда, не для одного и того же модуля. Некоторые инструменты на такое ругаются: https://lgtm.com/rules/1818040193/


Заключение


Для себя я выбираю следующий подход при импортировании и написании своих модулей.
Использовать import from, кроме случаев:


  • есть (или вероятен впоследствии) конфликт имён;
  • функции/классы модуля имеют короткие и распространённые имена (json);
  • существуют устоявшиеся традиции или конкретные рекомендации авторов модуля, например pytest.
Источник: habr.com
К списку статей
Опубликовано: 24.02.2021 00:19:22
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Python

Code style

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru