It seems they canceled in Python 3 all the easy ways to quickly load a script by removing execfile()
.
Is there an obvious alternative I'm missing?
It seems they canceled in Python 3 all the easy ways to quickly load a script by removing execfile()
.
Is there an obvious alternative I'm missing?
According to the documentation, instead of
execfile("./filename")
Use
exec(open("./filename").read())
See:
close
that file handle too. Another reason to dislike the change from python 2. –
Chaulmoogra filename
? Without having to exit and re-enter the python environment –
Scoff open
always needs a follow up call to close
docs.python.org/3.6/tutorial/… –
Chaulmoogra close
along side an open
call (or better yet use the with
statement), you never know how long a variable will linger for, where the code will be used from, nor where the code will end up being pasted. –
Chaulmoogra with
because im a forgetful person and 99% of the time forget to close the file, using with
eliminates this issue :) –
Edwinedwina globals()
as the second argument for exec
–
Sextet with open('./filename') as f: exec(f.read())
deals with opening and closing the file –
Naive ./
do? In other words, what is the difference (if any) between open("./filename")
and open("filename")
? –
Whisk PATH
and think the ./
means “(user-written) program”. –
Chihuahua 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:
exec
is a statement in python2, exec(code)
works because the parens just get ignored. –
Latarsha "somefile.py"
contained inspect.getsourcefile(lambda _: None)
which was failing without the compile, because the inspect
module couldn't determine where the code was coming from. –
Moffit open("somefile.py")
may be incorrect if somefile.py
uses a character encoding different from locale.getpreferredencoding()
. tokenize.open()
could be used instead. –
Loughlin compile()
will fail if the source code has trailing whitespace or uses line endings other than '\n'. –
Variation 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 file 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 in globals()
& 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 a init_globals
argument). The globals are returned.
execfile
executed in the current namespace or the given namespace. The semantics of locals
and globals
, 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).
file_globals
? This would save having to type the file_globals['...']
for every variable. –
Yvetteyvon 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)
execfile
. It even worked for my when using pytests where other solutions posted above failed. Thx! :) –
Waggish You could write your own function:
def xfile(afile, globalz=None, localz=None):
with open(afile, "r") as fh:
exec(fh.read(), globalz, localz)
If you really needed to...
globals
and locals
point to the global namespace fo the module containing the definition of execfile()
rather than to the global and local namespace of the caller. The correct approach is to use None
as default value and determine the caller's globals and locals via the introspection capabilities of the inspect
module. –
Tadzhik If the script you want to load is in the same directory than the one you run, maybe "import" will do the job ?
If you need to dynamically import code the built-in function __ import__ and the module imp are worth looking at.
>>> import sys
>>> sys.path = ['/path/to/script'] + sys.path
>>> __import__('test')
<module 'test' from '/path/to/script/test.pyc'>
>>> __import__('test').run()
'Hello world!'
test.py:
def run():
return "Hello world!"
If you're using Python 3.1 or later, you should also take a look at importlib.
importlib
dev.to/0xcrypto/dynamic-importing-stuff-in-python--1805 –
Rolph Here's what I had (file
is already assigned to the path to the file with the source code in both examples):
execfile(file)
Here's what I replaced it with:
exec(compile(open(file).read(), file, 'exec'))
My favorite part: the second version works just fine in both Python 2 and 3, meaning it's not necessary to add in version dependent logic.
Avoid exec()
if you can. For most applications, it's cleaner to make use of Python's import system.
This function uses built-in importlib
to execute a file as an actual module:
from importlib import util
def load_file_as_module(name, location):
spec = util.spec_from_file_location(name, location)
module = util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
Let's have a file foo.py
:
def hello():
return 'hi from module!'
print('imported from', __file__, 'as', __name__)
And import it as a regular module:
>>> mod = load_file_as_module('mymodule', './foo.py')
imported from /tmp/foo.py as mymodule
>>> mod.hello()
hi from module!
>>> type(mod)
<class 'module'>
This approach doesn't pollute namespaces or messes with your $PATH
whereas exec()
runs code directly in the context of the current function, potentially causing name collisions. Also, module attributes like __file__
and __name__
will be set correctly, and code locations are preserved. So, if you've attached a debugger or if the module raises an exception, you will get usable tracebacks.
Note that one minor difference from static imports is that the module gets imported (executed) every time you run load_file_as_module()
, and not just once as with the import
keyword.
load_file
twice for the same file will or will not reload the file (I wouldn't know without trying). –
Mo loader.exec_module()
somewhat suggests.) –
Genip Note that the above pattern will fail if you're using PEP-263 encoding declarations that aren't ascii or utf-8. You need to find the encoding of the data, and encode it correctly before handing it to exec().
class python3Execfile(object):
def _get_file_encoding(self, filename):
with open(filename, 'rb') as fp:
try:
return tokenize.detect_encoding(fp.readline)[0]
except SyntaxError:
return "utf-8"
def my_execfile(filename):
globals['__file__'] = filename
with open(filename, 'r', encoding=self._get_file_encoding(filename)) as fp:
contents = fp.read()
if not contents.endswith("\n"):
# http://bugs.python.org/issue10204
contents += "\n"
exec(contents, globals, globals)
share
link under it. To get a link to a comment, right-click on the timestamp and click "copy link address". –
Loughlin Also, while not a pure Python solution, if you're using IPython (as you probably should anyway), you can do:
%run /path/to/filename.py
Which is equally easy.
I'm just a newbie here so maybe it's pure luck if I found this :
After trying to run a script from the interpreter prompt >>> with the command
execfile('filename.py')
for which I got a "NameError: name 'execfile' is not defined" I tried a very basic
import filename
it worked well :-)
I hope this can be helpful and thank you all for the great hints, examples and all those masterly commented pieces of code that are a great inspiration for newcomers !
I use Ubuntu 16.014 LTS x64. Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux
© 2022 - 2024 — McMap. All rights reserved.
reload
is back, asimp.reload
, since 3.2. – Permeability%run script_name
works with all version of Python. – Reticentimp
isimportlib
(which must be imported):importlib.reload(mod_name)
imports and executesmod_name
. – Wagrunfile()
since I needed to run a Python script that executes in its own namespace (as opposed to executing on the calling namespace). My application: add the directory of the called script to the system path (sys.path
) using the__file__
attribute: if we useexecfile()
or its equivalent in Python 3 (exec(open('file.py').read())
) the included script is run in the calling namespace and thus__file__
resolves to the calling file name. – Jadotvillesys.argv
is really outside the scope of this function and has some (IMHO) unacceptable down-sides since the caller might be using sys.argv elsewhere. It's possible this could be temporarily overridden (which isn't thread-safe)... but might still be acceptable in some cases. Whatever the case - this wasn't supported by the original execfile, if you want to optionally pass environment, argv, working directory ... etc. This could be a separate answer. – Gladden