Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
>>> import this
...
Readability counts.
...
def square(x1, y1, x2, y2, x3, y3):
....
[global]
param = value
group.param1=value1
group.param2=value2
Собственно тут всё описано. Берём BASE_PATH и PROJECT_HOSTNAME из текстового конфига и вычисляем SOME_JOB_COMMAND в коде программы.
# settings.py
from constants import *
# а тут все вычисления
# КОНСТАНТЫ
...
# ВЫЧИСЛЯЕМЫЕ ЗНАЧЕНИЯ
...
Нормальный конфиг должен быть понятен человеку, не знающему питон.
FOO = 123 пишется одинаково что в ini, что в .py.простые каскады, отсутствие соблазна определить настройку «неправильно»
более внятные ошибки нежели ImportError
DEBUG = False
VAR = some_func(DEBUG)DEBUG = TrueDEBUG = False
try:
from settings_local import *
except ImportError:
pass
VAR = some_func(DEBUG)
BAR = some_func1(VAR)
DEBUG = True
VAR = True
try:
VAR
except NameError:
VAR = some_func(DEBUG))VAR = some_func(DEBUG)
if 'VAR' not in locals():
VAR = some_func(DEBUG)
def configure_from_files():
# la la la
return eval_values(result)
def eval_values(conf):
conf['VAR'] = conf['VAR'] or some_func(conf['DEBUG'])
conf['BAR'] = conf['BAR'] or some_func1(conf['VAR'])
eval_values протестировать в изоляции смогут.Понимаете в чём проблема? То, что мы перекрыли значение PROJECT_HOSTNAME абсолютно по барабану для итогового значения SOME_JOB_COMMAND.
# settings.py
BASE_PATH = os.path.dirname(__file__)
PROJECT_HOSTNAME = 'localhost'
try:
from settings_local import *
except ImportError:
pass
SOME_JOB_COMMAND = '%s/bin/do_job.py -H %s' % (BASE_PATH, PROJECT_HOSTNAME)
Мы могли бы скрипя зубами скопипастить определение SOME_JOB_COMMAND после перекрытия, но даже это не возможно: BASE_PATH то, в другом модуле.
# settings_local.py
from settings import *
# settings_local.py
from settings import *Угу… А если у нас SOME_JOB_COMMAND переопределён в settings_local? Или принять эту переменную, как железно вычисляемую, без возможности переопределения алгоритма вычисления?
# settings.py
BASE_PATH = os.path.dirname(__file__)
PROJECT_HOSTNAME = 'localhost'
try:
from settings_local import *
except ImportError:
pass
if 'SOME_JOB_COMMAND' not in locals():
SOME_JOB_COMMAND = '%s/bin/do_job.py -H %s' % (BASE_PATH, PROJECT_HOSTNAME)
В конце концов это даст возможность использовать конфиг людьми, не знающими языка.
# значения по умолчанию
from settings_local import *
# вычисляемые значения
Я уже не говорю о том, что исполняемый код в качестве конфигурации может просто приводить к трудноотлаживаемым ImportError при старте приложения в новой среде.
if 'BLAH_BLAH' not in locals():, но ugly же. Пример с ImportError чуть выше — циклический импорт.# settings_local.py
FOO = 'my value'
# settings.py
FOO = 'default value'
from settings_local import *
BAR = some_func(FOO)
# test_settings.py
INSTALLED_APPS.remove('my_app')
# test_settings.py
from settings import *
INSTALLED_APPS.remove('my_app')
'/usr/local/bin/do_job -H %s' % PROJECT_HOSTNAME и не захочу, чтобы затем её значение вернули «обратно».Config.PROJECT_HOSTNAME = 'localhost'
Config.SOME_JOB_COMMAND = lamda cfg: '%s/bin/do_job.py -H %s' % (cfg.BASE_PATH, cfg.PROJECT_HOSTNAME)
Config.PROJECT_HOSTNAME = 'somehost'
Антипаттерн settings.py