anthonio
Сен. 3, 2009 12:27:47
Имеем модуль, который никогда не будет запускаться, а из него будут выдёргиваться нужные функции. Эти функции также используют внешние модули/функции. Есть ли существенная разница в чём-либо (может в скорости) где происходит импорт этих внешних модулей, в начале (глобальное пространство имён) или непосредственно перед использованием в теле функции?
Так:
from blablabla import bla
def blo(*args, **kwargs):
bla()
...
или так
def blo(*args, **kwargs):
from blablabla import bla
bla()
...
Аргументируте свою точку зрения! :)
igor.kaist
Сен. 3, 2009 13:06:51
В функциях, имена сначала ищется в локальном пространстве имен, затем в глобальном. Поэтому с точки зрения производительности, второй вариант быстрее (мы говорим о каких то микросекундах). Но, лучше все же импортировать все модули в начале программы, так как будет меньше путаницы и трудно уловимых ошибок.
j2a
Сен. 3, 2009 15:11:51
Зависит от. Предпочитаю 1. По ситуации (слишком много мелких функций с разными импортами, циклические импорты и пр.) – 2.
про миллисекунды и скорость – это _обязательно_ нужно тестировать, потому что если функцию blo вызывают чёрти-сколько-раз, то не факт, что import+local lookup будет быстрее чем global lookup. Если же в функции blo чёрти-сколько-раз вызывается bla, то да – второй вариант быстрее.
Андрей Светлов
Сен. 3, 2009 16:18:14
igor.kaist, кажется, несколько погорячился.
Function call (который делается на опкод IMPORT_NAME при вызове __import__) значительно дороже dictionary lookup - даже если учесть тот факт, что все последующие импорты происходят довольно быстро и модуль находится в sys.modules.
К тому же на момент импорта происходит import lock - щелкает мьютекс, переключается PyEval_SaveThread/PyEval_RestoreThread. Долго.
И это не самое страшное. У меня была как-то неприятная проблема - в мультипоточном приложении была взаимная блокмровка на этот самый import lock. Выяснял проблему долго и мучительно. Тем более что она нестабильно воспроизводилась (а если честно - то вообще долгое время по свински всплывала только у пользователей и не хотела проявляться на девелоперских машинах).
Импорт из функции хоть и возможен - но использовать его стоит аккуратно.
Для того, чтобы не тянуть все сразу, используют другие техники.
Можно посмотреть на bzrlib.lazy_import или mercurial.demandimport
Да, еще - при
from mod import name
модуль тянется весь целиком.
Сначала идет IMPORT_NAME, потом IMPORT_FROM.
Если в подуле много мелких функций - то первое обращение затянет их все, как ни старайся.
igor.kaist
Сен. 3, 2009 16:57:31
Андрей Светлов, я,честно, несколько раз перечитывал ваше сообщение, но знаний не хватило понять, что же вы хотели сказать. Что быстрее то в итоге? :) // вот что значит настолько глубокие знания…
Андрей Светлов
Сен. 3, 2009 17:13:52
Вариант номер раз.
Чтобы программа не тянула все модули сразу - можно попробовать использовать demandimport.py из Mercurial HG.
Работает так: на import statement возвращается прокси, который будет делать импорт при первом реальном обращении.
Подход имеет несколько мелких ограничений (прокси - не модуль и проверка на isinstance не сработает) - но обычно вполне гож.
Поможет ускорить запуск программы - т.е. время до того, как на экране появится что-нибудь, веселящее пользователя своим видом.
Но это уже несколько другая задача.
Пятнадцать минут “аргументировал свою точку зрения” - а оказывается нужно было только пальцем ткнуть. :)
anthonio
Сен. 4, 2009 03:09:08
Что ж, спасибо всем, а Андрею Светлову – отдельная благодарность :)