Python: 'import *' vs execfile
В некоторых моих приложениях 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
Оба работают по назначению, но мне любопытно, не хватает ли я каких-либо ошибок, и вообще какой подход более рекомендуется и почему.
Ответы
Ответ 1
Использование функции 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
not execfile
. Django очень "согласуется с конфигурацией". Следуйте за соглашением.
Ответ 2
Другое отличие: 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
к глобалям.
Ответ 3
Первая версия (from settings_local import *
) - это то, что все ожидали бы увидеть. Он также позволит анализаторам кода найти модуль.