What is an alternative to execfile in Python 3?

前端 未结 12 1779
滥情空心
滥情空心 2020-11-22 02:33

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?

相关标签:
12条回答
  • 2020-11-22 03: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.

    0 讨论(0)
  • 2020-11-22 03:06

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

    0 讨论(0)
  • 2020-11-22 03:06

    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
    

    Usage example

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

    Advantages

    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.

    0 讨论(0)
  • 2020-11-22 03:07

    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.

    0 讨论(0)
  • 2020-11-22 03:10

    According to the documentation, instead of

    execfile("./filename") 
    

    Use

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

    See:

    • What’s New In Python 3.0
    0 讨论(0)
  • 2020-11-22 03:10

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

    0 讨论(0)
提交回复
热议问题