Как стать автором
Обновить

Комментарии 9

лично я чаще всего исхожу из принципа что именно гружу. такие модули как «os» имеет смысл грузить просто через import. самописанные библиотеки и просто разложенные по полочкам классы лучше грузить через from так как контроль имён всё равно на мне, а удлинять названия добавляя еще название модуля смысла не вижу. есть и исключения такие как glob.glob() — ну это всегда вызывает улыбку и проще через from загрузить и не париться. Тоже самое относиться к «from pathlib import Path». тут конечно уже велик шанс колизии имён, но я предпочитаю не покушаться на названия классов из стандартной поставки пайтона, так что свои «пути», называю просто более развернуто

так же я придерживаюсь практики говорящих названий функций и классов. это позволяет избежать колизий да и вообще улучшает читаемость. «get_habr_like_count()» — мало шансов что перечётся с иными функциями из других библиотек
Посмотрим, что под капотом:
from dis import dis

def foo():
    import math
    return math.pi

def bar():
    from math import pi
    return pi

dis(foo)
dis(bar)
Выхлоп будет примерно таким:
          foo()                |             bar()
                               |
#     import math              |  #     from math import pi
 0 LOAD_CONST       1 (0)      |   0 LOAD_CONST        1 (0)      
 2 LOAD_CONST       0 (None)   |   2 LOAD_CONST        2 (('pi',))
 4 IMPORT_NAME      0 (math)   |   4 IMPORT_NAME       0 (math)
 6 STORE_FAST       0 (math)   |   6 IMPORT_FROM       1 (pi)
                               |   8 STORE_FAST        0 (pi)
                               |  10 POP_TOP
#     return math.pi           |     
 8 LOAD_FAST        0 (math)   |  
10 LOAD_ATTR        1 (pi)     |  # return pi  
12 RETURN_VALUE                |  12 LOAD_FAST         0 (pi)
                               |  14 RETURN_VALUE  
Действительно, в обоих вариантах модуль импортируется целиком, что неудивительно — в модуле может быть код инициализации (а может и не быть).

Видна также выгода от импорта аттрибута модуля — при обращении к нему экономится аж целый LOAD_ATTR. Это очень быстрый опкод, но иногда хочется еще быстрее.
from timeit import timeit

setup = """
import math
from math import pi
def foo(): return math.pi
def bar(): return pi
def baz(): return __import__('math').pi"""

print(timeit('foo()', setup=setup))
print(timeit('bar()', setup=setup))
print(timeit('baz()', setup=setup))
Выхлоп:
0.09096475400019699
0.06547341800069262
0.221324110999376

Спасибо, за детальное исследование внутренностей.


25 миллисекунд разницы на миллион запусков набегает. Это именно то, что я имел ввиду под "разницы в производительности нет"

Отличная статья, а как влияет на импортирование модуля и классов из него условие if name == “main”?

Если модуль импортируется любым способом, то его __name__ != "__main__", всё что внутри if не выполняется.


А еще можно в этот процесс добавить немного магии и импортировать динамически созданные сущности: https://plumbum.readthedocs.io/en/latest/local_commands.html#import-hack

from module import *

нервно курит в сторонке

Импорт со звёздочкой идёт в лес.


В PEP8 даны достаточно однозначные рекомендации, которые не сложно соблюдать.


А еще flake8 умеет ругаться на использование F403 ‘from module import *’ used; unable to detect undefined names.

Полностью согласен, тем не менее во многих проектах встречаются использование импорта со звёздочкой при создании пакетов
# __init__.py
from .module_1 import *
from .module_2 import *
...

Это помогает создать удобную используемость, не нужно знать точное местоположение функций в иерархии пакетов (естественно при условии что имена будут уникальными).

Я предпочитаю явно задавать публичное API модуля.


При звёздочках надо заполнять __all__ или получишь всё что есть внутри. Если свои аттрибуты можно спрятать через правильное именование (начать с нижнего подчёрквания) то что делать с теми которые импортируешь?


from my_module import pprint

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации