[Python] Import or from import, that is the question
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Есть три стадии знаний: ты используешь инструмент, ты понимаешь как он работает, ты можешь учить других работать этим инструментом. Потихонечку начал перетекать в третью и стал задавать себе вопросы, которые раньше не задавал.
Например, что лучше: import module или from module import function?
Я решил разобраться в этом чуть поглубже, ответы на StackOverflow меня не удовлетворили.
Для тех, кому лень читать: все варианты хороши.
Советы от создателей языка
Обратимся к первоисточникам, а именно — к PEP8
Когда импортируете класс из модуля, будет нормально сделать это так:
from myclass import MyClass
from foo.bar.yourclass import YourClass
Если это вызывает локальный конфликт имён, то можно сделать это явно:
import myclass
import foo.bar.yourclass
И использовать как myclass.MyClass и foo.bar.yourclass.YourClass
PEP-8 поддерживает оба подхода и даёт некоторые рекомендации.
Кто принимает решение?
Тот, кто пишет модуль. Обычно модули пишутся без оглядки на конкретный способ импорта и можно использовать любой подход. Но в целом это вопрос дизайна модуля, поэтому у его автора могут быть конкретные рекомендации и модуль может быть написан с прицелом на конкретный вариант импорта.
Документация
Самый очевидный способ продемонстрировать как пользоваться библиотекой, — документация. Не ту документацию, которую никто не читает, а примеры использования.
"Фляжка" и "бутылка" идут по пути точечных импортов.
from flask import Flask
app = 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 pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
В случае пайтеста это вполне логичный выбор, так как эта библиотека должна быть максимально совместима со всем кодом на планете.
У неё один из самых высоких шансов получить локальный конфликт имён.
Есть даже плагин для линтера который проверяет, что импорты оформлены правильно.
Имена атрибутов модуля
Второй подход основан на выборе имён внутри модуля. Для очень абстрактных имён, например как в некоторых модулях стандартной библиотеки лучше использовать импорт из модуля.
import json
json.load(...)
json.loads(...)
json.dump(...)
json.dumps(...)
Без импорта модуля имена теряют контекст и могут внести путаницу.
from pickle import load
from marshal import dumps
from xmlrpc.client import loads
from 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 plt
import numpy as np
import pandas as pd
Единообразие
На мой взгляд, использование обоих подходов не сильно нарушает единообразие, и можно их спокойно смешивать. Желательно, правда, не для одного и того же модуля. Некоторые инструменты на такое ругаются: https://lgtm.com/rules/1818040193/
Заключение
Для себя я выбираю следующий подход при импортировании и написании своих модулей.
Использовать import from, кроме случаев:
- есть (или вероятен впоследствии) конфликт имён;
- функции/классы модуля имеют короткие и распространённые имена (json);
- существуют устоявшиеся традиции или конкретные рекомендации авторов модуля, например pytest.
===========
Источник:
habr.com
===========
Похожие новости:
- [Python, Мозг] Мой опыт работы с EEG гарнитурой EMOTIV EPOC+
- [Разработка веб-сайтов, Python, API] Как я сделал веб-фреймворк без MVC — Pipe Framework
- [Python, .NET, История IT] Языку программирования Python исполнилось 30 лет
- [Системное администрирование, Python, *nix, Серверное администрирование, DevOps] Improving Ansible (перевод)
- [Python] Pythonista. Привет, Python
- [Python, Машинное обучение, Искусственный интеллект, Natural Language Processing] Краткость — сестра таланта: Как сделать Transformer/Summarizer на Trax
- [Python, Программирование] Еще один фреймворк…
- Языку Python исполнилось 30 лет
- [Тестирование IT-систем, Python, Карьера в IT-индустрии, VueJS] Дайджест митапов и практикумов: Frontend, Web, QA и не только
- [Информационная безопасность, Криптография, Python, Графические оболочки, C] Поддержка токенов PKCS#11 с ГОСТ-криптографией в Python. Часть I
Теги для поиска: #_python, #_python, #_code_style, #_python
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:41
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Есть три стадии знаний: ты используешь инструмент, ты понимаешь как он работает, ты можешь учить других работать этим инструментом. Потихонечку начал перетекать в третью и стал задавать себе вопросы, которые раньше не задавал. Например, что лучше: import module или from module import function? Я решил разобраться в этом чуть поглубже, ответы на StackOverflow меня не удовлетворили. Для тех, кому лень читать: все варианты хороши. Советы от создателей языка Обратимся к первоисточникам, а именно — к PEP8 Когда импортируете класс из модуля, будет нормально сделать это так: from myclass import MyClass
from foo.bar.yourclass import YourClass Если это вызывает локальный конфликт имён, то можно сделать это явно: import myclass
import foo.bar.yourclass И использовать как myclass.MyClass и foo.bar.yourclass.YourClass PEP-8 поддерживает оба подхода и даёт некоторые рекомендации. Кто принимает решение? Тот, кто пишет модуль. Обычно модули пишутся без оглядки на конкретный способ импорта и можно использовать любой подход. Но в целом это вопрос дизайна модуля, поэтому у его автора могут быть конкретные рекомендации и модуль может быть написан с прицелом на конкретный вариант импорта. Документация Самый очевидный способ продемонстрировать как пользоваться библиотекой, — документация. Не ту документацию, которую никто не читает, а примеры использования. "Фляжка" и "бутылка" идут по пути точечных импортов. from flask import Flask
app = 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 pytest
def test_zero_division(): with pytest.raises(ZeroDivisionError): 1 / 0 В случае пайтеста это вполне логичный выбор, так как эта библиотека должна быть максимально совместима со всем кодом на планете. У неё один из самых высоких шансов получить локальный конфликт имён. Есть даже плагин для линтера который проверяет, что импорты оформлены правильно. Имена атрибутов модуля Второй подход основан на выборе имён внутри модуля. Для очень абстрактных имён, например как в некоторых модулях стандартной библиотеки лучше использовать импорт из модуля. import json
json.load(...) json.loads(...) json.dump(...) json.dumps(...) Без импорта модуля имена теряют контекст и могут внести путаницу. from pickle import load
from marshal import dumps from xmlrpc.client import loads from 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 plt
import numpy as np import pandas as pd Единообразие На мой взгляд, использование обоих подходов не сильно нарушает единообразие, и можно их спокойно смешивать. Желательно, правда, не для одного и того же модуля. Некоторые инструменты на такое ругаются: https://lgtm.com/rules/1818040193/ Заключение Для себя я выбираю следующий подход при импортировании и написании своих модулей. Использовать import from, кроме случаев:
=========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:41
Часовой пояс: UTC + 5