在python3中execfile的替代方案是什么?

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

我是否错过了一个明显的选择?

371576 次浏览

如果你想要加载的脚本和你运行的脚本在同一个目录中,也许“import”就可以了?

如果你需要动态导入代码,内置函数__ import__和模块小鬼值得一看。

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

你可以写自己的函数:

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

如果你真的需要…

您只需读取文件并自己执行代码。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)

(并不严格需要compile调用,但它将文件名与code对象关联起来,使调试更容易一些。)

看到的:

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

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

.

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

根据文档,而不是

execfile("./filename")

使用

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

看到的:

由于在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不仅可以执行文件,还可以执行卵和目录(详细信息请参阅其文档)。

以下是我所拥有的(在两个例子中,file已经被分配给了源代码文件的路径):

execfile(file)

下面是我用它替换的:

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

我最喜欢的部分是:第二个版本在Python 2和3中都工作得很好,这意味着不需要添加版本相关的逻辑。

虽然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()

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

%run /path/to/filename.py

这同样简单。

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

尝试运行脚本后,从解释器提示>>>与命令

    execfile('filename.py')

为此我得到了一个“NameError: name 'execfile' is not defined”,我尝试了一个非常基本的

    import filename

它工作得很好:-)

我希望这能对你有所帮助,感谢大家提供的提示、示例和所有那些对新手有很大启发的注释代码!

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

.

如果可以的话,避免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关键字那样只导入一次。