What is an alternative to execfile in Python 3?
According to the documentation, instead of
execfile("./filename")
Use
exec(open("./filename").read())
See:
- What’s New In Python 3.0
You are just supposed to read the file and exec the code yourself. 2to3 current replaces
execfile("somefile.py", global_vars, local_vars)
as
with open("somefile.py") as f:
code = compile(f.read(), "somefile.py", 'exec')
exec(code, global_vars, local_vars)
(The compile call isn't strictly needed, but it associates the filename with the code object making debugging a little easier.)
See:
- http://docs.python.org/release/2.7.3/library/functions.html#execfile
- http://docs.python.org/release/3.2.3/library/functions.html#compile
- http://docs.python.org/release/3.2.3/library/functions.html#exec
While exec(open("filename").read())
is often given as an alternative to execfile("filename")
, it misses important details that execfile
supported.
The following function for Python3.x is as close as I could get to having the same behavior as executing a file directly. That matches running python /path/to/somefile.py
.
def execfile(filepath, globals=None, locals=None):
if globals is None:
globals = {}
globals.update({
"__file__": filepath,
"__name__": "__main__",
})
with open(filepath, 'rb') as file:
exec(compile(file.read(), filepath, 'exec'), globals, locals)
# execute the file
execfile("/path/to/somefile.py")
Notes:
-
Uses binary reading to avoid encoding issues
-
Guaranteed to close the file (Python3.x warns about this)
-
Defines
__main__
, some scripts depend on this to check if they are loading as a module or not for eg.if __name__ == "__main__"
-
Setting
__file__
is nicer for exception messages and some scripts use__file__
to get the paths of other files relative to them. -
Takes optional globals & locals arguments, modifying them in-place as
execfile
does - so you can access any variables defined by reading back the variables after running. -
Unlike Python2's
execfile
this does not modify the current namespace by default. For that you have to explicitly pass inglobals()
&locals()
.
As suggested on the python-dev mailinglist recently, the runpy module might be a viable alternative. Quoting from that message:
https://docs.python.org/3/library/runpy.html#runpy.run_path
import runpy file_globals = runpy.run_path("file.py")
There are subtle differences to execfile
:
-
run_path
always creates a new namespace. It executes the code as a module, so there is no difference between globals and locals (which is why there is only ainit_globals
argument). The globals are returned.execfile
executed in the current namespace or the given namespace. The semantics oflocals
andglobals
, if given, were similar to locals and globals inside a class definition. run_path
can not only execute files, but also eggs and directories (refer to its documentation for details).
This one is better, since it takes the globals and locals from the caller:
import sys
def execfile(filename, globals=None, locals=None):
if globals is None:
globals = sys._getframe(1).f_globals
if locals is None:
locals = sys._getframe(1).f_locals
with open(filename, "r") as fh:
exec(fh.read()+"\n", globals, locals)