Является ли pythonic импортировать внутри функции?

PEP 8 говорит:

  • Импорт всегда помещается в верхнюю часть файла сразу после любого модуля комментарии и docstrings, а также перед модульными глобалями и константами.

В то время я нарушаю PEP 8. Несколько раз я импортирую материал внутри функций. Как правило, я делаю это, если есть импорт, который используется только в одной функции.

Любые мнения?

EDIT (причина, по которой я чувствую, что импорт в функции может быть хорошей идеей):

Основная причина: он может сделать код более понятным.

  • При просмотре кода функции я могу спросить себя: "Что такое function/class xxx?" (xxx используется внутри функции). Если у меня есть весь мой импорт в верхней части модуля, я должен посмотреть туда, чтобы определить, что такое xxx. Это больше проблема при использовании from m import xxx. Видеть m.xxx в функции, вероятно, говорит мне больше. В зависимости от того, что m: Это хорошо известный модуль/пакет верхнего уровня (import m)? Или это подмодуль/пакет (from a.b.c import m)?
  • В некоторых случаях наличие этой дополнительной информации ( "Что такое xxx?" ) близко к тому, где используется xxx, может облегчить понимание функции.

Ответ 1

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

Если я добавлю новый код в существующий файл, я, как правило, сделаю импорт там, где он нужен, а затем, если код останется, я сделаю вещи более перманентными, перемещая строку импорта до вершины файла.

Еще один момент, я предпочитаю получить исключение ImportError до того, как будет запущен какой-либо код - как проверка работоспособности, так что еще одна причина для импорта вверху.

Я использую pyChecker для проверки неиспользуемых модулей.

Ответ 2

Есть два случая, когда я нарушаю PEP 8 в этом отношении:

  • Циркулярный импорт: модуль A импортирует модуль B, но что-то в модуле B нуждается в модуле A (хотя это часто является признаком того, что мне нужно реорганизовать модули для устранения циклической зависимости)
  • Вставка точки останова pdb: import pdb; pdb.set_trace() Это удобно b/c. Я не хочу помещать import pdb в начало каждого модуля, который я могу отлаживать, и легко запомнить удаление импорта, когда я удалите точку останова.

Вне этих двух случаев, это хорошая идея, чтобы все было наверху. Это делает зависимости более ясными.

Ответ 3

Вот четыре варианта использования импорта, которые мы используем

  • importfrom x import y и import x as y) вверху

  • Выбор для импорта. Вверху.

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
    
  • Условный импорт. Используется с JSON, XML-библиотеками и т.п. Вверху.

    try:
        import this as foo
    except ImportError:
        import that as foo
    
  • Динамический импорт. Пока что у нас есть только один пример этого.

    import settings
    module_stuff = {}
    module= __import__( settings.some_module, module_stuff )
    x = module_stuff['x']
    

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

    Это также больше или меньше в верхней части модуля


Вот что мы делаем, чтобы сделать код более понятным:

  • Держите модули короткими.

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

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

Ответ 4

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

Если вы занимаетесь IronPython, мне говорят, что лучше импортировать внутренние функции (поскольку компиляция кода в IronPython может быть медленной). Таким образом, вы можете получить возможность импортировать внутренние функции. Но кроме этого, я бы сказал, что это просто не стоит бороться с конвенцией.

Как правило, я делаю это, если есть импорт, который используется только в одной функции.

Еще один момент, который я хотел бы сделать, заключается в том, что это может быть потенциальной проблемой обеспечения. Что произойдет, если вы добавите функцию, которая использует модуль, который ранее использовался только одной функцией? Не хотите ли добавить импорт в начало файла? Или вы собираетесь сканировать каждую функцию для импорта?

FWIW, бывают случаи, когда имеет смысл импортировать внутри функции. Например, если вы хотите установить язык в cx_Oracle, вам нужно установить переменную среды NLS _ LANG перед импортом. Таким образом, вы можете увидеть такой код:

import os

oracle = None

def InitializeOracle(lang):
    global oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    oracle = cx_Oracle

Ответ 5

Я нарушил это правило раньше для модулей, которые самотестируются. То есть, они обычно используются только для поддержки, но я определяю их для них, поэтому, если вы их запускаете самостоятельно, вы можете проверить их функциональность. В этом случае я иногда импортирую getopt и cmd только в основном, потому что я хочу, чтобы кто-то читал код, что эти модули не имеют ничего общего с нормальной работой модуля и только включены для тестирования.

Ответ 6

Пока он import, а не from x import *, вы должны поместить их вверху. Он добавляет только одно имя в глобальное пространство имен, и вы придерживаетесь PEP 8. Кроме того, если вам в дальнейшем понадобится это где-то еще, вам не нужно ничего перемещать.

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

Ответ 7

Исходя из вопроса о загрузке модуля дважды - Почему бы не обойти?

Импорт в верхней части script укажет на зависимости и другой импорт в функции, сделав эту функцию более атомной, и, по-видимому, не приведет к снижению производительности, поскольку последовательный импорт дешев.