413

似乎他们在 Python 3 中取消了通过删除快速加载脚本的所有简单方法execfile()

有没有我想念的明显替代方案?

4

12 回答 12

462

根据文档,而不是

execfile("./filename") 

采用

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

看:

于 2013-05-16T01:03:00.203 回答
235

您应该自己阅读文件并执行代码。2to3 电流替换

execfile("somefile.py", global_vars, local_vars)

作为

with open("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code, global_vars, local_vars)

(编译调用不是严格需要的,但它将文件名与代码对象相关联,使调试​​更容易一些。)

看:

于 2009-01-13T03:20:59.960 回答
83

虽然exec(open("filename").read())通常作为 的替代品execfile("filename"),但它错过了execfile支持的重要细节。

Python3.x 的以下函数与直接执行文件的行为一样接近。那匹配运行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")

笔记:

  • 使用二进制读取来避免编码问题

  • 保证关闭文件(Python3.x 对此发出警告)

  • 定义__main__,一些脚本依赖于此来检查它们是否作为模块加载,例如。if __name__ == "__main__"

  • 设置__file__对于异常消息更好,一些脚本用于__file__获取其他文件相对于它们的路径。

  • 采用可选的全局变量和局部变量参数,就地修改它们execfile- 因此您可以访问通过在运行后读回变量定义的任何变量。

  • 与 Python2 不同,默认情况下execfile不会修改当前命名空间。为此,您必须明确传入globals()& locals()

于 2017-01-15T06:08:36.907 回答
75

正如最近在 python-dev邮件列表中所建议的那样,runpy模块可能是一个可行的替代方案。引用该消息:

https://docs.python.org/3/library/runpy.html#runpy.run_path

import runpy
file_globals = runpy.run_path("file.py")

有细微的差别execfile

  • run_path总是创建一个新的命名空间。它将代码作为模块执行,因此全局变量和局部变量之间没有区别(这就是为什么只有一个init_globals参数)。全局变量被返回。

    execfile在当前命名空间或给定命名空间中执行。和的语义localsglobals如果给定的话,类似于类定义中的局部变量和全局变量。

  • run_path不仅可以执行文件,还可以执行egg和目录(详见其文档)。

于 2014-06-17T10:06:15.690 回答
22

这个更好,因为它从调用者那里获取全局变量和本地变量:

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)
于 2010-05-17T12:43:26.833 回答
16

您可以编写自己的函数:

def xfile(afile, globalz=None, localz=None):
    with open(afile, "r") as fh:
        exec(fh.read(), globalz, localz)

如果你真的需要...

于 2009-01-12T17:38:43.523 回答
14

如果您要加载的脚本与您运行的脚本位于同一目录中,那么“导入”可能会完成这项工作吗?

如果需要动态导入代码,内置函数__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!'

测试.py:

def run():
        return "Hello world!"

如果您使用的是 Python 3.1 或更高版本,您还应该查看importlib

于 2009-01-12T17:28:15.367 回答
10

这是我所拥有的(file在两个示例中都已分配给带有源代码的文件的路径):

execfile(file)

这是我替换它的内容:

exec(compile(open(file).read(), file, 'exec'))

我最喜欢的部分:第二个版本在 Python 2 和 3 中都可以正常工作,这意味着不需要添加依赖于版本的逻辑。

于 2014-10-07T13:39:03.413 回答
6

exec()如果可以,请避免。对于大多数应用程序,使用 Python 的导入系统会更干净。

此函数使用 built-inimportlib将文件作为实际模块执行:

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

使用示例

让我们有一个文件foo.py

def hello():
    return 'hi from module!'
print('imported from', __file__, 'as', __name__)

并将其作为常规模块导入:

>>> mod = load_file_as_module('mymodule', './foo.py')
imported from /tmp/foo.py as mymodule
>>> mod.hello()
hi from module!
>>> type(mod)
<class 'module'>

好处

这种方法不会污染名称空间或弄乱您的 while$PATH直接exec()在当前函数的上下文中运行代码,从而可能导致名称冲突。此外,模块属性如__file____name__将被正确设置,并保留代码位置。因此,如果您附加了调试器或模块引发异常,您将获得可用的回溯。

请注意,与静态导入的一个细微差别是,每次运行时都会导入(执行)模块load_file_as_module(),而不是像import关键字那样只导入一次。

于 2020-01-27T19:18:46.370 回答
5

请注意,如果您使用不是 ascii 或 utf-8 的 PEP-263 编码声明,上述模式将失败。您需要找到数据的编码,并在将其交给 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)
于 2011-04-13T00:43:54.057 回答
3

此外,虽然不是纯 Python 解决方案,但如果您使用的是 IPython(无论如何您可能应该这样做),您可以执行以下操作:

%run /path/to/filename.py

这同样容易。

于 2017-01-15T06:10:24.520 回答
1

我只是这里的新手,所以如果我发现这个可能是纯粹的运气:

尝试使用命令从解释器提示符 >>> 运行脚本后

    execfile('filename.py')

为此我得到一个“NameError:名称'execfile'未定义”我尝试了一个非常基本的

    import filename

它运作良好:-)

我希望这会有所帮助,并感谢大家的精彩提示、示例和所有那些对新手来说是一个很大的灵感的大师级注释代码片段!

我使用 Ubuntu 16.014 LTS x64。 Linux 上的 Python 3.5.2(默认,2016 年 11 月 17 日,17:05:23)[GCC 5.4.0 20160609]

于 2017-02-11T23:23:28.423 回答