69

Python 2 had the builtin function execfile, which was removed in Python 3.0. This question discusses alternatives for Python 3.0, but some considerable changes have been made since Python 3.0.

What is the best alternative to execfile for Python 3.2, and future Python 3.x versions?

Community
  • 1
  • 1
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526

4 Answers4

77

The 2to3 script replaces

execfile(filename, globals, locals)

by

exec(compile(open(filename, "rb").read(), filename, 'exec'), globals, locals)

This seems to be the official recommendation. You may want to use a with block to ensure that the file is promptly closed again:

with open(filename, "rb") as source_file:
    code = compile(source_file.read(), filename, "exec")
exec(code, globals, locals)

You can omit the globals and locals arguments to execute the file in the current scope, or use exec(code, {}) to use a new temporary dictionary as both the globals and locals dictionary, effectively executing the file in a new temporary scope.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 3
    Why is this better than Lennart's version? – Matt Joiner Jun 15 '11 at 23:07
  • @Matt: The advantages are (a) error message will include the correct filename and (b) it seems to be the official recommendation, so maybe there are advantages we aren't aware of. If you omit the `globals` and `locals` parameters, it will also work in all versions of Python. – Sven Marnach Jun 16 '11 at 00:21
  • I know this is the official recommendation, but with this I get these: "ResourceWarning: unclosed file <_io.TextIOWrapper name='..." errors. It's just out test runner so it doesn't matter much, but still.. – VPeric Nov 03 '11 at 11:20
  • @VPeric: On a release build of Python, this warning should be silenced by default. Quite valid point, though. – Sven Marnach Nov 03 '11 at 11:54
  • @VPeric: I've created an [issue in Python's bug tracker](http://bugs.python.org/issue13332) for this. – Sven Marnach Nov 03 '11 at 12:19
  • @Sven Thanks! I've added myself to the nosy there, too. Still, if I tried to use the solution you provided there for my code, I get the following error: "SyntaxError: unqualified exec is not allowed in function 'test_file' it contains a nested function with free variables" So yeah, again, this isn't so important but I'd like to fix the leaks. (and it could help us spot other warnings) – VPeric Nov 03 '11 at 22:24
  • @VPeric: Your problem is completely unrelated to both this SO question and the Python bug tracker issue, which both deal with the question of how to rewrite `execfile()` in Python 3.x. You are using Python 2.7, so all this isn't relevant for you. I explained in [this comment](http://stackoverflow.com/questions/6357361/alternative-to-execfile-in-python-3-2/6357529#comment9780515_6357529) what your actual problem is. – Sven Marnach Nov 03 '11 at 23:24
  • This has a problem with default system encoding (e.g. on Windows). – anatoly techtonik Dec 05 '13 at 02:27
  • @techtonik: Thanks. I guess opening the file in binary mode and having `compile()` figure out the right encoding should fix this -- I updated the answer accordingly. – Sven Marnach Dec 05 '13 at 12:50
  • I thought that relying on file's destructor to close the file is considered a bad practice. – cubuspl42 Dec 05 '13 at 13:06
  • @SvenMarnach it may be Python docs issue, but binary `bytes` [are not listed](http://docs.python.org/3/library/functions.html#compile) among accepted inputs for `compile()`. – anatoly techtonik Dec 05 '13 at 13:49
  • @techtonik: I know it's not documented, but `compile()` does actually accept `bytes`, and it respects any encoding specification in the source code to decode it to a string, so I think it's the most robust way to do this. – Sven Marnach Dec 05 '13 at 14:45
  • 1
    @SvenMarnach, if you can post a link to official recommendation or source code (so that people can be sure it won't be "fixed" in future), I'd give it a +1. =) – anatoly techtonik Dec 06 '13 at 11:49
  • @techtonik: It's the only reasonable behaviour, so it won't change. Here's a link to the current source code of importlib, which uses `compile()` on a `bytes` object: http://hg.python.org/cpython/file/9bce03920afe/Lib/importlib/_bootstrap.py#l1533 – Sven Marnach Dec 09 '13 at 18:20
  • Doesn't seems to work on 3.4.3: `TypeError: exec() arg 2 must be a dict, not builtin_function_or_method` – kenorb May 02 '15 at 13:06
  • 1
    @kenorb: It does work in Python 3.4. You apparently tried to use the last line without replacing `locals` and `globals` with whatever you want to have there instead. They are just placeholders, I can't know what you want to pass in, or whether you want to omit them altogether. I consider this the "official" recommendation because this is how the "official" 2to3 tool migrates `execfile()` calls. – Sven Marnach May 03 '15 at 15:44
  • thanks. Can anyone please explain the significance of local and global arguments here? – Vinay Mar 30 '20 at 03:12
  • 1
    @vinaygarg These are dictionaries with the global and lcoal variables the file is supposed to be executed within. You can omit them to execute the file in the current scope. A common alternative is to use `exec(..., {})` to execute the file in a new temporary scope. – Sven Marnach Mar 30 '20 at 08:04
  • Shouldn't `globals()` and `locals()` be executed functions? – Aidas Bendoraitis Jul 13 '20 at 10:49
  • 1
    @AidasBendoraitis I used `globals` and `locals` as variable names here; I could just as well have used `x` and `y` or whatever. You usually wouldn't do `exec(code, globals(), locals())`, since this would be the same as just `exec(code)`. – Sven Marnach Jul 13 '20 at 11:54
67
execfile(filename)

can be replaced with

exec(open(filename).read())

which works in all versions of Python

Newer versions of Python will warn you that you didn't close that file, so then you can do this is you want to get rid of that warning:

with open(filename) as infile:
    exec(infile.read())

But really, if you care about closing files, you should care enough to not use exec in the first place.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • 1
    Why is this better than Sven's version? – Matt Joiner Jun 15 '11 at 23:07
  • 17
    @Matt: It's simpler? – Lennart Regebro Jun 16 '11 at 03:07
  • Must be something due to my code, but when I use this instead of execfile, I get: "SyntaxError: unqualified exec is not allowed in function 'test_file' it contains a nested function with free variables" (in Python 2.7) – VPeric Nov 03 '11 at 11:22
  • 1
    @VPeric: In Python 2.x, you need to use the `exec ... in ...` form of `exec` in such a situation. For example `exec code in globals()` will execute the code in the module's global namespace. Note that the exec'ed code can't change local variables in a way that is reliably visible by the nested function. – Sven Marnach Nov 03 '11 at 13:02
  • @Sven I'm actually trying to write code that will work in both version (in py3k after 2to3, of course) and preferably close files it opens (unlike what 2to3 currently does automatically). None of the stuff on this page works. We are probably just relying on some obscure detail, but I can't figure it out. The code is [here](https://github.com/sympy/sympy/blob/master/sympy/utilities/runtests.py) (search for execfile). If you wouldn't mind taking a look, I'd be much obliged! :) – VPeric Nov 04 '11 at 08:58
  • 2
    @VPeric: All of the stuff here works, if you have a specific problem, make it a question. – Lennart Regebro Nov 06 '11 at 15:49
  • File doesnt have to be closed? – Philipp Apr 22 '16 at 12:27
  • 1
    No, it will be closed when garbage collected, so it doesn't have to (although it's a good idea to close it). – Lennart Regebro Apr 22 '16 at 15:57
  • This answer does not fit my needs, as the executed file cannot be inspected. For example, it cannot know its own directory. – fffred Sep 16 '16 at 15:23
  • Can I use this for executing environment module initialization file? – srand9 Jan 30 '17 at 08:42
  • Possibly, but you probably shouldn't. – Lennart Regebro Jan 30 '17 at 14:10
  • This is the only answer that actually works. – Devon Apr 15 '19 at 18:28
  • The answer works but I get this warning: ResourceWarning: unclosed file – shevy Nov 10 '19 at 15:49
  • Yes. As mentioned elsewhere, you really shouldn't do this, first of all, so why you care about a warning is beyond me. :-) But I'll update my answer. – Lennart Regebro Nov 11 '19 at 12:56
9

In Python3.x this is the closest thing I could come up with to executing a file directly, that matches running python /path/to/somefile.py.

Notes:

  • Uses binary reading to avoid encoding issues
  • Garenteed 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.
def exec_full(filepath):
    global_namespace = {
        "__file__": filepath,
        "__name__": "__main__",
    }
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), global_namespace)

# Execute the file.
exec_full("/path/to/somefile.py")
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • i have this as the old version: execfile(join(dirname(__file__), 'ExcelLibrary', 'version.py')) so with the new.... exec(open(filename).read()) how does that become? – tijnn Jun 22 '20 at 17:07
  • @tijnn it can't be done (easily) in a single line, that's why I've provided a function - `exec_full` – ideasman42 Nov 27 '20 at 07:32
4

Standard runpy.run_path is an alternative.

eudoxos
  • 18,545
  • 10
  • 61
  • 110