Локальные операторы импорта в Python

Я использовал экран больше 10 лет и вероятно использую меньше чем половину функций. Таким образом, определенно не необходимо изучить все свои функции сразу же (и я не рекомендовал бы пробовать). Мои ежедневные команды:

^A ^W - window list, where am I
^A ^C - create new window
^A space - next window
^A p - previous window
^A ^A - switch to previous screen (toggle)
^A [0-9] - go to window [0-9]
^A esc - copy mode, which I use for scrollback

я думаю вот именно. Я иногда использую функции разделения экрана, но конечно не ежедневно. Другая подсказка - то, если экран, кажется, заперся, потому что Вы поражаете некоторую комбинацию случайного ключа случайно, сделайте и ^Q и ^A ^Q, чтобы попытаться разблокировать его.

44
задан Mike Pennington 16 May 2012 в 04:13
поделиться

6 ответов

В других ответах возникает небольшая путаница относительно того, как import действительно работает.

Это утверждение:

import foo

примерно эквивалентно этому утверждению:

foo = __import__('foo', globals(), locals(), [], -1)

That то есть, он создает переменную в текущей области с тем же именем, что и запрошенный модуль, и назначает ей результат вызова __ import __ () с этим именем модуля и множеством аргументов по умолчанию.

__ import __ () обрабатывает концептуальное преобразование строки ( 'foo' ) в объект модуля. Модули кэшируются в sys.modules , и это первое место, куда смотрит __ import __ () - если sys.modules имеет запись для 'foo' , то это what __ import __ ('foo') вернет, что бы это ни было. Это действительно не так не заботится о типе. Вы можете сами увидеть это в действии; попробуйте запустить следующий код:

import sys
sys.modules['boop'] = (1, 2, 3)
import boop
print boop

Оставив на данный момент в стороне стилистические соображения, наличие оператора импорта внутри функции работает так, как вы хотите. Если модуль никогда раньше не импортировался, он импортируется и кэшируется в sys.modules. Затем он назначает модуль локальной переменной с этим именем. Он не , не не изменяет какое-либо состояние на уровне модуля. Он , возможно, изменяет какое-то глобальное состояние (добавляя новую запись в sys.modules).

Тем не менее, я почти никогда не использую import внутри функции. Если импорт модуля вызывает заметное замедление работы вашей программы - например, он выполняет длительные вычисления при статической инициализации, или это просто массивный модуль, - и ваша программа на самом деле редко нуждается в модуле для чего-либо, это Совершенно нормально иметь импорт только внутри функций, в которых он используется. (Если это было неприятно, Гвидо прыгнул бы в свою машину времени и изменил бы Python, чтобы мы не могли этого сделать.) Но, как правило, я и все сообщество Python помещали все наши операторы импорта в верхнюю часть модуля в области видимости модуля.

72
ответ дан 26 November 2019 в 21:53
поделиться

См. PEP 8 :

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

Обратите внимание, что это чисто стилистический выбор, поскольку Python будет обрабатывать все операторы import одинаково, независимо от того, где они объявлены в исходном файле. Тем не менее, я бы порекомендовал вам следовать общепринятой практике, так как это сделает ваш код более читаемым для других.

12
ответ дан 26 November 2019 в 21:53
поделиться

Не говоря уже о стиле, это истина, что импортированный модуль будет импортирован только один раз (если для указанного модуля не вызывается reload ). Однако каждый вызов import Foo будет неявно проверять, загружен ли этот модуль (путем проверки sys.modules ).

Также следует учитывать «разборку» двух в противном случае равные функции, когда один пытается импортировать модуль, а другой нет:

>>> def Foo():
...     import random
...     return random.randint(1,100)
... 
>>> dis.dis(Foo)
  2           0 LOAD_CONST               1 (-1)
              3 LOAD_CONST               0 (None)
              6 IMPORT_NAME              0 (random)
              9 STORE_FAST               0 (random)

  3          12 LOAD_FAST                0 (random)
             15 LOAD_ATTR                1 (randint)
             18 LOAD_CONST               2 (1)
             21 LOAD_CONST               3 (100)
             24 CALL_FUNCTION            2
             27 RETURN_VALUE        
>>> def Bar():
...     return random.randint(1,100)
... 
>>> dis.dis(Bar)
  2           0 LOAD_GLOBAL              0 (random)
              3 LOAD_ATTR                1 (randint)
              6 LOAD_CONST               1 (1)
              9 LOAD_CONST               2 (100)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE        

Я не уверен, насколько больше байт-код транслируется для виртуальной машины, но если это был важный внутренний цикл для вашей программы, вы Я бы определенно хотел придать некоторый вес подходу Bar по сравнению с подходом Foo .

Быстрый и грязный тест timeit действительно показывает небольшое улучшение скорости при использовании Bar :

$ python -m timeit -s "from a import Foo,Bar" -n 200000 "Foo()"
200000 loops, best of 3: 10.3 usec per loop
$ python -m timeit -s "from a import Foo,Bar" -n 200000 "Bar()"
200000 loops, best of 3: 6.45 usec per loop
10
ответ дан 26 November 2019 в 21:53
поделиться

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

Предположим, я этого не делаю; Предположим, я добавляю его локально в свою функцию. А затем предположим, что в какой-то момент я или кто-то еще добавляет кучу других функций, которые используют StringIO . Этот человек собирается взглянуть на верхнюю часть модуля и добавить import StringIO . Теперь ваша функция содержит код, который не только неожиданный, но и избыточный.

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

Изменить:

Фактически, оказывается, что все это ерунда.

Импорт модуля не изменяет состояние уровня модуля (он инициализирует импортируемый модуль, если ничего еще не произошло, но это совсем не то же самое). Импорт модуля, который вы уже импортировали где-то еще, ничего не стоит вам, кроме поиска в sys.modules и создания переменной в локальной области.

Зная это, я чувствую себя глупым, исправляя все проблемы. места в моем коде, где я это исправил, но это мой крест.

8
ответ дан 26 November 2019 в 21:53
поделиться

Когда интерпретатор Python встречает оператор импорта, он начинает читать все определения функций в импортируемом файле. Это объясняет, почему иногда импорт может занять некоторое время.

Идея, лежащая в основе выполнения всего импорта с самого начала, ЯВЛЯЕТСЯ стилистической условностью, как указывает Эндрю Хэйр. Однако вы должны иметь в виду, что, поступая таким образом, вы неявно заставляете интерпретатор проверять, был ли этот файл уже импортирован после первого импорта. Это также становится проблемой, когда ваш файл кода становится большим, и вы хотите «обновить» свой код, чтобы удалить или заменить определенные зависимости. Это потребует от вас поиска всего файла кода, чтобы найти все места, куда вы импортировали этот модуль.

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

3
ответ дан 26 November 2019 в 21:53
поделиться

Я вижу два способа, когда вам нужно импортировать его локально

  1. Для тестирования или для временного использования, вам нужно что-то импортировать, в этом случае вы должны поместить импорт в место использования.

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

В противном случае всегда ставьте его на первое место для эффективности и последовательности.

0
ответ дан 26 November 2019 в 21:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: