Импорт Python на уровне функций VS.Уровень модуля - PullRequest
6 голосов
/ 27 января 2012

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

следующий импорт импортируется только при вызове функции?

     def func():
         from task import test

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

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

Являются ли эти справедливые предположения, что я совершенно не прав?

Ответы [ 3 ]

6 голосов
/ 27 января 2012

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

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

Я импортирую модули в область действия функции только по двум причинам: 1) для устранения проблем циклического импорта, которые, между прочим, могут быть решены другими способами путем рефакторинга, или 2) если модуль является необязательным, иэта функция не используется многими моими пользователями.В случае 2) модуль может полностью отсутствовать, и проблем не будет, если кто-то не вызовет функцию.

3 голосов
/ 27 января 2012

Давайте посмотрим, как будет выглядеть байт-код для следующих двух функций:

def func1():
    """ test imported each time function is run """
    from task import test
    test()

def func2():
    """ test was imported at top of module """
    test()

Как вы можете видеть ниже, func2() экономит много шагов, используя глобально импортированную функцию test.

>>> dis.dis(func1)
  3           0 LOAD_CONST               1 (-1)
              3 LOAD_CONST               2 (('test',))
              6 IMPORT_NAME              0 (task)
              9 IMPORT_FROM              1 (test)
             12 STORE_FAST               0 (test)
             15 POP_TOP

  4          16 LOAD_FAST                0 (test)
             19 CALL_FUNCTION            0
             22 POP_TOP
             23 LOAD_CONST               3 (None)
             26 RETURN_VALUE
>>> dis.dis(func2)
  3           0 LOAD_GLOBAL              0 (test)
              3 CALL_FUNCTION            0
              6 POP_TOP
              7 LOAD_CONST               1 (None)
             10 RETURN_VALUE

Принятие этого во внимание заранее, вероятно, является преждевременной оптимизацией, как указано в комментарии Делнана.

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

0 голосов
/ 27 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...