In some of my Django apps I'm using a settings_local.py
file to override settings that are different on various environments (e.g. development, test and production). I have originally used the following code to include its contents in the settings.py
:
try:
from settings_local import *
except ImportError:
sys.stderr.write("The settings_local.py file is missing.\n")
DEBUG=False
I have recently found the execfile
function and switched to something like:
try:
execfile(path.join(PROJECT_ROOT, "settings_local.py"))
except IOError:
sys.stderr.write("The settings_local.py file is missing.\n"
DEBUG=False
Both work as intended, but I'm curious whether I'm missing any gotchas, and in general which approach is more recommended and why.
Using
execfile
function will result in the evaluation of the Python source file (.py) every time the settings file is evaluated. You are executing the Python parser each time. Usingimport
wouldn't necessarily do this (might use the .pyc file). Generally the first time you run a project in Python (at least, cPython) it gets compiled to bytecode and not recompiled again. You are breaking that. This isn't necessarily a problem, but you should be aware of it.Using
execfile
will also result in all of the imports you may have in thesettings_local.py
file being re-evaluated in the module scope of thesettings.py
file. Usingimport *
would have included all items in thesettings_local.py
module scope. The net effect is the same (all items included insettings_local.py
module scope are included insettings.py
) but the method is different.Finally, it's normal for modules to be executed as modules rather than included. It is reasonable for code to include things such as
os.path.dirname(__file__)
. If any code did use this, you would confuse it as the code would no longer be executing in the module that the author might reasonably have expected.In my experience, people use
import
notexecfile
. Django is very much 'convention over configuration'. Follow the convention.The first version (
from settings_local import *
) is what everyone would expect to see. It will also let code analyzers find the module.Another difference: execfile gets a context dictionary; the global context by default or a specified dictionary. This could allow some strange things
dont_do_this.py
:Obviously,
fails.
However,
is OK and results in
d=={'x':1, 'z':2}
Note that
is OK and results in the variable
z
being added to the globals.