看起来他们在Python 3中取消了所有快速加载脚本的简单方式,通过移除execfile()
。
我是否遗漏了一些明显的替代方案?
看起来他们在Python 3中取消了所有快速加载脚本的简单方式,通过移除execfile()
。
我是否遗漏了一些明显的替代方案?
execfile("./filename")
使用
exec(open("./filename").read())
请参见:
您只需要阅读文件并自己执行代码。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)
exec
是一个语句,但exec(code)
也可以工作,因为括号会被忽略。 - medmundssomefile.py
使用的字符编码不同于locale.getpreferredencoding()
,则open("somefile.py")
可能是不正确的。可以使用tokenize.open()
代替。 - jfscompile()
将失败。 - itsadok虽然 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()
。
最近在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
在当前命名空间或给定的命名空间中执行。如果给定了locals
和globals
的语义类似于类定义内部的局部变量和全局变量。
run_path
不仅可以执行文件,还可以执行egg和目录(有关详细信息,请参阅其文档)。
file_globals
中?这样可以避免为每个变量键入 file_globals['...']
。 - Adriaan这个更好,因为它从调用者那里获取全局和局部的变量:
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)
execfile
。即使在使用其他上面发布的解决方案失败时,它也适用于我的pytests。谢谢! :) - Boriel你可以编写自己的函数:
def xfile(afile, globalz=None, localz=None):
with open(afile, "r") as fh:
exec(fh.read(), globalz, localz)
如果您确实需要...
globals
和locals
都指向包含execfile()
定义的模块的全局命名空间,而不是调用者的全局和本地命名空间。正确的方法是使用None
作为默认值,并通过inspect
模块的内省能力确定调用者的全局和本地命名空间。 - Sven Marnach如果你想要加载的脚本与你运行的脚本在同一个目录中,也许"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!"
importlib
方面做得很好 https://dev.to/0xcrypto/dynamic-importing-stuff-in-python--1805 - Nick Brady以下是我所拥有的(在这两个例子中,file
已经被指定为包含源代码文件的路径):
execfile(file)
我替换成了以下内容:
exec(compile(open(file).read(), file, 'exec'))
我最喜欢的部分是,第二个版本在 Python 2 和 3 中都能正常工作,这意味着不需要添加与版本相关的逻辑。
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
关键字。
load_file
函数是否会重新加载文件来扩展它(如果没有尝试,我就不知道)。 - gerritloader.exec_module()
的名称所暗示的那样,它在每次调用时都会被(重新)执行。) - Arminiusclass 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)
reload
已经回归,作为3.2版本之后的imp.reload
。 - Danica%run script_name
适用于所有版本的Python。 - Michaelimp
模块被替换为必须先导入的importlib
模块。使用importlib.reload(mod_name)
可以重新导入并执行mod_name
模块。 - P. Wormerrunfile()
的功能,因为我需要运行一个在其自己的命名空间中执行的 Python 脚本(与在 调用 命名空间中执行相反)。 我的应用程序:使用__file__
属性将被调用脚本的目录添加到系统路径 (sys.path
) 中:如果我们使用execfile()
或其 Python 3 中的等效方法 (exec(open('file.py').read())
),则包含的脚本将在调用命名空间中运行,因此__file__
解析为 调用 文件名。 - mastropisys.argv
真的超出了此函数的范围,并且有一些(在我看来)不可接受的缺点,因为调用者可能在其他地方使用sys.argv
。这可能会被暂时覆盖(这不是线程安全的)...但在某些情况下仍然可以接受。无论如何 - 这不是原始 execfile 支持的,如果您想要可选地传递环境、argv、工作目录等,则可以提供一个单独的答案。 - ideasman42