By R S


2009-01-12 17:23:36 8 Comments

It seems they canceled in Python 3 all the easy way to quickly load a script by removing execfile()

Is there an obvious alternative I'm missing?

11 comments

@ideasman42 2017-01-15 06:08:36

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 in globals() & locals().

@Pedro Vagner 2013-05-16 01:03:00

According to the documentation, instead of

execfile("./filename") 

Use

exec(open("./filename").read())

See:

@JoeyC 2014-02-20 00:20:47

Any idea why they would do such a thing? This is so much more verbose than before. Also, it doesn't work for me on Python3.3. I get "No such file or directory" when I exec(open('./some_file').read()). I have tried including the '.py' extension and also excluding the './' as well

@Wok 2014-07-29 06:37:55

Simple and it works as intended for text file. You can even get the output by adding a comma before the last bracket and the name of the output variable.

@KDN 2015-07-27 19:57:58

Less trivially, this doesn't provide line numbers when exceptions are raised, as did execfile().

@Rebs 2015-10-19 05:02:06

You'll need to close that file handle too. Another reason to dislike the change from python 2.

@airdas 2016-11-30 12:43:38

How do you reload imported modules within filename ? Without having to exit and re-enter the python environment

@tiho 2017-02-01 20:16:42

@Rebs you don't need to close the file handle in that example, it will be done automatically (at least in regular CPython)

@Rebs 2017-02-01 23:55:10

@tiho How so? A call to open always needs a follow up call to close docs.python.org/3.6/tutorial/…

@tiho 2017-02-02 16:45:28

@Rebs in CPython objects are garbage-collected as soon as their reference count goes to 0, only circular references may delay this (stackoverflow.com/questions/9449489/…). In that case that should happen right after read() returns. And file objects are closed on deletion (NB: I realize this link explicitly says "always close files", which is indeed good practice to follow in general)

@Rebs 2017-02-03 00:59:56

@tiho Interesting, I was under the impression the object wasn't smart enough to close itself. Thanks for opening my eyes to this. I think its still good practice to put a 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.

@WhatsThePoint 2017-02-06 13:48:21

@Rebs i always use with because im a forgetful person and 99% of the time forget to close the file, using with eliminates this issue :)

@francek 2017-05-09 18:44:48

how can I pass arguments to this "exec(open("./filename").read())" command ? For example I have a file with data called input_data.csv and want to pass it to script, thanks

@jkmartindale 2018-06-21 21:59:58

Some weird edge cases involving executing a file that updates already defined functions and classes can be fixed by including globals() as the second argument for exec

@Homero Esmeraldo 2018-08-07 13:46:44

with open('./filename') as f: exec(f.read()) deals with opening and closing the file

@javadba 2018-10-01 05:28:53

@JonathanHartley The question "why do such a thing" remains unanswered. These things do add up.

@Jonathan Hartley 2018-10-01 12:24:18

@javadba Yeah, fair enough. But the reason seems clear enough. exec already executed python from any readable stream, while execfile did it just for those readable streams that are open files. You don't need both. Like adding parents to print, the cost is slightly longer user code, but the benefits are that code is more explicit (see "Zen") while the language is simpler (and hence easier to learn and remember)

@javadba 2018-10-01 14:13:14

Don't get me started on that zen. My first significant program in ruby took three days - most of it on the problem itself. In three weeks it was an end to end custom ETL system having dozens of dynamic sqls. Python? I've been doing major projects in it every year since 2012 and am far from comfortable in it.

@Jonathan Hartley 2018-10-02 15:48:51

That's interesting to hear, and there's probably some really significant and interesting details about mismatches of your prior mental models and the like. For readers' benefit though, it's probably worth mentioning that your experience is an unusual outlier. One of the strongest and most common sentiments people associate with learning Python is that it's so easy. One of the significant contributors to that is precisely this sort of backwards-incompatible pruning of the language.

@mpb 2018-12-14 16:56:04

What does the ./ do? In other words, what is the difference (if any) between open("./filename") and open("filename")?

@Davis Herring 2019-02-16 19:41:24

@mpb: Nothing: some people don’t understand PATH and think the ./ means “(user-written) program”.

@Claude 2017-02-11 23:23:28

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

@R S 2017-01-15 06:10:24

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.

@ArtOfWarfare 2014-10-07 13:39:03

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.

@Jonas Schäfer 2014-06-17 10:06:15

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).

@John Donn 2017-01-08 12:00:10

For some reason, it outputs to the screen a lot of information it was not asked to print ('builtins' etc in Anaconda Python 3). Is there some way to turn this off so that only the information which I output with print() gets visualized?

@Adriaan 2017-08-17 08:03:28

Is it also possible to get all the variables in the current workspace instead of them all being stored in file_globals? This would save having to type the file_globals['...'] for every variable.

@Jonas Schäfer 2018-04-11 08:54:28

@Adriaan globals().update(file_globals)

@Evan Fosmark 2009-01-12 17:38:43

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...

@nosklo 2009-08-22 13:33:45

-1: the exec statment doesn't work this way. Code doesn't run in any version of python.

@Brian 2009-12-27 10:30:03

-1: Not reliable. Some uses of execfile are incompatible.

@Sven Marnach 2011-11-03 13:20:21

-1: The default parameter values are evaluated at function definition time, making both 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.

@Benjamin Peterson 2009-01-13 03:20:59

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:

@Nathan Shively-Sanders 2009-05-21 20:27:17

This works for me. However, I noticed that you've written the local and global arguments in the wrong order. It's actually: exec(object[, globals[, locals]]). Of course if you had the arguments flipped in the original, then 2to3 will produce exactly what you said. :)

@medmunds 2013-03-05 05:25:14

Was pleased to discover that, if you can omit global_vars and local_vars, the python3 replacement here works under python2 as well. Even though exec is a statement in python2, exec(code) works because the parens just get ignored.

@ArtOfWarfare 2014-10-07 13:35:07

+1 for using compile. My "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.

@aneccodeal 2015-03-26 23:29:57

That's... really ugly. Any idea why they got rid of execfile() in 3.x? execfile also made it easy to pass commandline args.

@jfs 2016-03-23 14:39:27

open("somefile.py") may be incorrect if somefile.py uses a character encoding different from locale.getpreferredencoding(). tokenize.open() could be used instead.

@itsadok 2017-11-14 15:27:55

Another caveat: in python 2, compile() will fail if the source code has trailing whitespace or uses line endings other than '\n'.

@ascobol 2009-01-12 17:28:15

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.

@Eric 2011-04-13 00:43:54

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)

@ArtOfWarfare 2014-10-07 13:15:49

What is "the above pattern"? Please use links when referring to other posts on StackOverflow. Relative positioning terms like "the above" don't work, as there are 3 different ways of sorting answers (by votes, by date, or by activity) and the most common one (by votes) is volatile. Over time your post and posts around yours will end up with different scores, meaning they'll be rearranged and such comparisons will be less useful.

@Eric 2014-10-07 17:33:48

Very good point. And given that I wrote this answer almost six months ago, I assume by "above pattern" I meant stackoverflow.com/a/2849077/165082 (which unfortunately you have to click on to resolve), or better still Noam's answer:

@ArtOfWarfare 2014-10-07 17:37:19

Generally when I want to refer to other answers to the same question from my answer, I type "Noam's Answer" (for example) and link the text to the answer I'm referring to, just for in case the answer becomes disassociated from the user in the future, IE, because the user changes their account name or the post becomes a communal wiki because too many edits have been made on it.

@DevPlayer 2015-04-08 14:42:38

How do you get the URL to a specific "answer" with in a post, excluding the poster's name of the answer?

@Eric 2015-04-08 19:07:27

View the source and get the ID. For example, your question would be stackoverflow.com/questions/436198/… . I'm all for a better method, but don't see anything when I hover near the comment

@DevPlayer 2015-04-09 13:32:12

@Eric Comment Reply Attempt Not related to answer; just trying out commenting trick mentioned by Eric. Also In Google Chrome right-click-Inspect Element helps find the comment ID.

@jfs 2016-03-23 14:45:23

@Eric: to get a link to an answer: click share link under it. To get a link to a comment, right-click on the timestamp and click "copy link address".

@Eric 2016-03-24 16:27:54

@J.F.Sebastian Noted.

@Noam 2010-05-17 12:43:26

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)

@Boriel 2019-06-14 11:06:02

Actually, this one is the closer to py2 execfile. It even worked for my when using pytests where other solutions posted above failed. Thx! :)

Related Questions

Sponsored Content

21 Answered Questions

[SOLVED] Does Python have a ternary conditional operator?

15 Answered Questions

[SOLVED] How to print to stderr in Python?

29 Answered Questions

[SOLVED] What does if __name__ == "__main__": do?

23 Answered Questions

[SOLVED] What is the difference between @staticmethod and @classmethod?

16 Answered Questions

[SOLVED] What are metaclasses in Python?

60 Answered Questions

[SOLVED] How do you split a list into evenly sized chunks?

57 Answered Questions

[SOLVED] Calling an external command in Python

10 Answered Questions

10 Answered Questions

[SOLVED] Does Python have a string 'contains' substring method?

38 Answered Questions

[SOLVED] What does the "yield" keyword do?

Sponsored Content