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

时间:2009-01-12 17:23:36

标签: python python-3.x

似乎他们在Python 3中取消了删除execfile()

快速加载脚本的所有简单方法

我是否有一个明显的选择?

12 个答案:

答案 0 :(得分:326)

According to the documentation,而不是

execfile("./filename") 

使用

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

请参阅:

答案 1 :(得分:201)

您应该自己阅读文件并执行代码。 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)

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

请参阅:

答案 2 :(得分:56)

虽然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__来获取与其相关的其他文件的路径。
  • 选择全局变量& locals参数,就像execfile那样就地修改它们 - 所以你可以通过在运行后读回变量来访问任何定义的变量。

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

答案 3 :(得分:52)

最近作为suggested on the 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的语义类似于类定义中的locals和globals。

  • run_path不仅可以执行文件,还可以执行鸡蛋和目录(有关详细信息,请参阅其文档)。

答案 4 :(得分:18)

您可以编写自己的函数:

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

如果你真的需要......

答案 5 :(得分:17)

这个更好,因为它接受来自调用者的全局变量和本地变量:

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)

答案 6 :(得分:11)

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

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

def run():
        return "Hello world!"

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

答案 7 :(得分:8)

这里有我的内容(file已经分配到文件的路径,并在两个示例中都包含源代码):

execfile(file)

这是我用以下内容替换它:

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

我最喜欢的部分:第二版在Python 2和3中都运行得很好,这意味着它不需要添加依赖于版本的逻辑。

答案 8 :(得分:5)

请注意,如果您使用的是PEP-263编码声明,则上述模式将失败 这不是ascii或utf-8。您需要找到数据的编码并对其进行编码 在将其交给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)

答案 9 :(得分:3)

此外,虽然不是纯粹的Python解决方案,但如果您正在使用IPython(无论如何应该如此),您可以这样做:

%run /path/to/filename.py

这同样容易。

答案 10 :(得分:1)

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

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

    execfile('filename.py')

我得到了一个“NameError:name'execfile'没有定义”我尝试了一个非常基本的

    import filename

效果很好: - )

我希望这对您有所帮助,并感谢大家提供的精彩提示,示例和所有精心评论的代码,这对新手来说是一个很好的灵感!

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

答案 11 :(得分:1)

请尽量避免使用exec()。对于大多数应用程序而言,使用Python的导入系统会更清洁。

此函数使用内置的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

用法示例

我们有一个文件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'>

优势

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

请注意,与静态导入相比,一个较小的区别是模块每次运行load_file_as_module()都会被导入(执行),而不仅仅是import关键字一次。