Python: 'import *' vs execfile
Asked Answered
M

3

13

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.

Maletta answered 28/7, 2012 at 17:46 Comment(0)
F
14

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. Using import 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 the settings_local.py file being re-evaluated in the module scope of the settings.py file. Using import * would have included all items in the settings_local.py module scope. The net effect is the same (all items included in settings_local.py module scope are included in settings.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 not execfile. Django is very much 'convention over configuration'. Follow the convention.

Fronia answered 28/7, 2012 at 19:12 Comment(6)
__file__ could be easily provided via arguments. The main difference that a module is imported exactly once no matter how many times import module is executed (exec executes the file every time it is called), and import doesn't require an explicit path to the file (so it would work inside a zip archive too).Trichology
@J.F.Sebastian That should be an answer.Inspirational
One advantage I found about execfile (as opposed to import) is that i can do it dynamically. Specifically, if I have a list of settings modules, I can do a loop through the list, calling execfile on each. Is there a way to do that with import instead?Maletta
Why would you want to do it dynamically though? How complex could your deployment possibly be?Fronia
Namely, importing uses the sys.modules cache to avoid reimporting a module that's already been imported.Beef
Is there any advantage in using execfile?Prem
K
9

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:

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

Obviously,

from dont_do_this import *

fails.

However,

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

is OK and results in d=={'x':1, 'z':2}

Note that

x=1
execfile( 'dont_do_this.py' )

is OK and results in the variable z being added to the globals.

Kipton answered 2/11, 2012 at 17:57 Comment(0)
D
2

The first version (from settings_local import *) is what everyone would expect to see. It will also let code analyzers find the module.

Drooff answered 28/7, 2012 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.