Python: «импорт *» против исполняемого файла

В некоторых из моих приложений Django я использую файл settings_local.py для переопределения настроек, которые различаются в разных средах (например, разработка, тестирование и производство). Первоначально я использовал следующий код, чтобы включить его содержимое в settings.py:

try:
    from settings_local import *
except ImportError:
    sys.stderr.write("The settings_local.py file is missing.\n")
    DEBUG=False

Недавно я нашел функцию execfile и переключился на что-то вроде:

try:
    execfile(path.join(PROJECT_ROOT, "settings_local.py"))
except IOError:
    sys.stderr.write("The settings_local.py file is missing.\n"
    DEBUG=False

Оба работают по назначению, но мне любопытно, пропускаю ли я какие-либо ошибки, и вообще, какой подход более рекомендуется и почему.


person Berislav Lopac    schedule 28.07.2012    source источник


Ответы (3)


Использование функции execfile приведет к оценке исходного файла Python (.py) каждый раз при оценке файла настроек. Вы каждый раз запускаете парсер Python. Использование import не обязательно сделает это (можно использовать файл .pyc). Обычно при первом запуске проекта на Python (по крайней мере, cPython) он компилируется в байт-код и больше не перекомпилируется. Вы нарушаете это. Это не обязательно проблема, но вы должны знать об этом.

Использование execfile также приведет к тому, что все импорты, которые могут быть в файле settings_local.py, будут переоценены в области модуля файла settings.py. Использование import * включало бы все элементы в область действия модуля settings_local.py. Чистый эффект тот же (все элементы, включенные в область модуля settings_local.py, включены в settings.py), но метод отличается.

Наконец, модули обычно выполняются как модули, а не включаются. Разумно, чтобы код включал такие вещи, как os.path.dirname(__file__). Если бы какой-либо код действительно использовал это, вы бы запутались, так как код больше не выполнялся бы в модуле, который мог разумно ожидать автор.

По моему опыту, люди используют import, а не execfile. Django во многом является «соглашением, а не конфигурацией». Следуйте конвенции.

person Joe    schedule 28.07.2012
comment
__file__ можно легко указать с помощью аргументов. Основное отличие состоит в том, что модуль импортируется ровно один раз, независимо от того, сколько раз выполняется import module (exec выполняет файл каждый раз, когда он вызывается), а import не требует явного пути к файлу (поэтому он будет работать внутри zip-архива). тоже архив). - person jfs; 28.07.2012
comment
@ J.F.Sebastian Это должен быть ответ. - person Marcin; 29.07.2012
comment
Одно преимущество, которое я нашел в execfile (в отличие от импорта), заключается в том, что я могу делать это динамически. В частности, если у меня есть список модулей настроек, я могу сделать цикл по списку, вызывая execfile для каждого. Есть ли способ сделать это с помощью импорта? - person Berislav Lopac; 29.07.2012
comment
Почему вы хотите сделать это динамически? Насколько сложным может быть ваше развертывание? - person Joe; 29.07.2012
comment
А именно, импорт использует кэш sys.modules, чтобы избежать повторного импорта модуля, который уже был импортирован. - person asmeurer; 26.07.2013

Еще одно отличие: execfile получает контекстный словарь; глобальный контекст по умолчанию или указанный словарь. Это может позволить некоторые странные вещи

dont_do_this.py:

# Probably not a good thing to do
z=x+1  # an expression that involves an un-defined field

Очевидно,

from dont_do_this import *

терпит неудачу.

Однако,

d={'x':1}
execfile( 'dont_do_this.py', d )

в порядке и приводит к d=={'x':1, 'z':2}

Обратите внимание, что

x=1
execfile( 'dont_do_this.py' )

в порядке и приводит к тому, что переменная z добавляется к глобальным.

person Dave    schedule 02.11.2012

Первая версия (from settings_local import *) — это то, что все ожидают увидеть. Это также позволит анализаторам кода найти модуль.

person thebjorn    schedule 28.07.2012