简体   繁体   English

Python 3 中 execfile 的替代方法是什么?

[英]What is an alternative to execfile in Python 3?

It seems they canceled in Python 3 all the easy way to quickly load a script by removing execfile()似乎他们在 Python 3 中取消了通过删除execfile()快速加载脚本的所有简单方法

Is there an obvious alternative I'm missing?我缺少一个明显的替代方案吗?

According to the documentation , instead of 根据文档,而不是

execfile("./filename") 

Use

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

See:看:

You are just supposed to read the file and exec the code yourself.您只应该阅读文件并自己执行代码。 2to3 current replaces 2to3 电流替换

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.) (并不严格需要 compile 调用,但它将文件名与代码对象相关联,使调试​​更容易一些。)

See:看:

While exec(open("filename").read()) is often given as an alternative to execfile("filename") , it misses important details that execfile supported.虽然exec(open("filename").read())通常被用作execfile("filename")的替代,但它execfile支持的重要细节。

The following function for Python3.x is as close as I could get to having the same behavior as executing a file directly. Python3.x 的以下函数与直接执行文件的行为非常接近。 That matches running python /path/to/somefile.py .这匹配运行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)保证关闭文件(Python3.x 对此有警告)
  • Defines __main__ , some scripts depend on this to check if they are loading as a module or not for eg.定义__main__ ,一些脚本依赖于此来检查它们是否作为模块加载,例如。 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.设置__file__对异常消息更好,一些脚本使用__file__来获取其他文件相对于它们的路径。
  • 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.采用可选的 globals 和 locals 参数,像execfile一样就地修改它们 - 这样您就可以访问通过在运行后读回变量定义的任何变量。

  • Unlike Python2's execfile this does not modify the current namespace by default.与 Python2 的execfile不同,默认情况下它不会修改当前命名空间。 For that you have to explicitly pass in globals() & locals() .为此,您必须明确传入globals()locals()

As suggested on the python-dev mailinglist recently, the runpy module might be a viable alternative.正如最近在 python-dev邮件列表中所建议的runpy模块可能是一个可行的替代方案。 Quoting from that message:引用该消息:

https://docs.python.org/3/library/runpy.html#runpy.run_path 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 : execfile有细微的差别:

  • run_path always creates a new namespace. run_path总是创建一个新的命名空间。 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).它将代码作为模块执行,因此全局变量和init_globals变量之间没有区别(这就是为什么只有一个init_globals参数)。 The globals are returned.返回全局变量。

    execfile executed in the current namespace or the given namespace.在当前命名空间或给定命名空间中执行的execfile The semantics of locals and globals , if given, were similar to locals and globals inside a class definition. localsglobals的语义(如果给定)类似于类定义中的 locals 和 globals。

  • run_path can not only execute files, but also eggs and directories (refer to its documentation for details). run_path不仅可以执行文件,还可以执行eggs和目录(详见其文档)。

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)

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...如果你真的需要...

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__和模块imp值得一看。

>>> 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:测试.py:

def run():
        return "Hello world!"

If you're using Python 3.1 or later, you should also take a look at importlib .如果您使用 Python 3.1 或更高版本,您还应该查看importlib

Here's what I had ( file is already assigned to the path to the file with the source code in both examples):下面是我有什么( file已经被分配到的路径与在这两个例子中的源代码文件):

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.我最喜欢的部分:第二个版本在 Python 2 和 3 中都可以正常工作,这意味着没有必要添加依赖于版本的逻辑。

Note that the above pattern will fail if you're using PEP-263 encoding declarations that aren't ascii or utf-8.请注意,如果您使用的 PEP-263 编码声明不是 ascii 或 utf-8,则上述模式将失败。 You need to find the encoding of the data, and encode it correctly before handing it to exec().您需要找到数据的编码,并在将其交给 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)

Avoid exec() if you can.如果可以,请避免使用exec() For most applications, it's cleaner to make use of Python's import system.对于大多数应用程序,使用 Python 的导入系统更干净。

This function uses built-in importlib to execute a file as an actual module:此函数使用内置的importlib将文件作为实际模块执行:

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 :让我们有一个文件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.这种方法不会污染命名空间或弄乱您的$PATHexec()直接在当前函数的上下文中运行代码,可能会导致名称冲突。 Also, module attributes like __file__ and __name__ will be set correctly, and code locations are preserved.此外,诸如__file____name__类的模块属性将被正确设置,并保留代码位置。 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_as_module()时都会导入(执行)模块,而不是像import关键字那样只import一次。

Also, while not a pure Python solution, if you're using IPython (as you probably should anyway), you can do:此外,虽然不是纯 Python 解决方案,但如果您使用的是 IPython(无论如何您可能应该这样做),您可以执行以下操作:

%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为此我得到了一个“NameError: name 'execfile' is not defined”我尝试了一个非常基本的

    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.我使用 Ubuntu 16.014 LTS x64。 Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux Linux 上的 Python 3.5.2(默认值,2016 年 11 月 17 日,17:05:23)[GCC 5.4.0 20160609]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM