我当时在进行一些故障排除,我很好奇是否可以交互运行python脚本,更改脚本中定义的功能,保存文件,然后让交互式外壳程序识别更改。这是我目前正在做的一个例子:
my_script.py:
def dummy_func():
print('Something')
def main():
dummy_func()
if __name__ == '__main__':
main()
我去终端并运行:
>python -i my_script.py
Something
>>>
如果我在编辑器中返回my_script.py并进行以下更改:
def dummy_func():
print('Something else')
然后返回到终端(仍处于打开状态)并重新运行更新的功能:
>>>dummy_func()
Something
>>>
是否可以做点什么来代替以下行为?
>>>dummy_func()
Something else
>>>
我知道可以使用importlib重新加载模块,然后重新加载,但据我所知这不适用于此处,因为我没有导入任何内容。我对stackoverflow还是比较陌生,所以请告诉我是否需要提供更多详细信息或以其他方式询问。谢谢。
编辑;我认为这可能与How do I unload (reload) a Python module?不同。
我问是否有一种方法可以通过python shell重新加载正在交互运行的当前文件,而该问题询问如何重新加载已导入到另一个python脚本中的模块。我修改了答案,以包括对该问题的引用。
答案 0 :(得分:2)
从我可以找到的简短答案是:
否,通常,一旦文件被解析,分析并输入到解释器中,Python解释器就无法识别该文件的更改。
您显然应该做的是将.py文件用作模块,将其作为模块导入另一个.py文件,然后运行该新文件。这使您的第一个文件可以通过交互式解释器重新加载。这是example:
from importlib import reload # Python 3.4+ only.
import foo
while True:
# Do some things.
if is_changed(foo):
foo = reload(foo)
我仍然对细节有些模糊,但是也许有人可以帮忙填写这些。据我从下面链接的源中得知,解释器基本上采取了一些步骤从保存的python文件中加载程序。进入内存(在很多细节上都有光泽)。一旦执行了该过程,除非您明确要求它执行,否则解释器不会再次执行该过程,例如,使用importlib的reload()函数再次执行该过程。
来源:
How do I unload (reload) a Python module?(上面引用)
A Python Interpreter Written in Python:
该链接提供了有关解释器如何工作的更多信息,我发现本节特别有用:
Real Python字节码
在这一点上,我们将放弃玩具说明 设置并切换为真实的Python字节码。字节码的结构是 类似于我们的玩具解释器的详细说明集,除了 它使用一个字节而不是一个长名称来标识每条指令。 要了解这种结构,我们将逐步介绍 短功能。考虑下面的示例:>>> def cond(): ... x = 3 ... if x < 5: ... return 'yes' ... else: ... return 'no' ...
Python在运行时公开了其内部组件,我们可以正确地访问它们 来自REPL。对于功能对象cond,cond。代码是代码 与之关联的对象,并进行cond。代码。co_code是字节码。 几乎没有理由直接使用这些属性 当您编写Python代码时,但是它们确实允许我们起步 各种恶作剧-并查看内部以了解 他们。
>>> cond.__code__.co_code # the bytecode as raw bytes b'd\x01\x00}\x00\x00|\x00\x00d\x02\x00k\x00\x00r\x16\x00d\x03\x00Sd\x04\x00Sd\x00\x00S' >>> list(cond.__code__.co_code) # the bytecode as numbers [100, 1, 0, 125, 0, 0, 124, 0, 0, 100, 2, 0, 107, 0, 0, 114, 22, 0, 100, 3, 0, 83, 100, 4, 0, 83, 100, 0, 0, 83]
当我们只打印字节码时,它 看起来难以理解-我们只能说它是一系列字节。 幸运的是,我们可以使用一个强大的工具来了解它: Python标准库中的模块。
dis是字节码反汇编程序。反汇编器采用低级代码 为机器编写的代码,例如汇编代码或字节码,以及 以易于阅读的方式打印。当我们运行dis.dis时,它输出一个 字节码已通过的解释。
>>> dis.dis(cond) 2 0 LOAD_CONST 1 (3) 3 STORE_FAST 0 (x) 3 6 LOAD_FAST 0 (x) 9 LOAD_CONST 2 (5) 12 COMPARE_OP 0 (<) 15 POP_JUMP_IF_FALSE 22 4 18 LOAD_CONST 3 ('yes') 21 RETURN_VALUE 6 >> 22 LOAD_CONST 4 ('no') 25 RETURN_VALUE 26 LOAD_CONST 0 (None) 29 RETURN_VALUE
这是什么意思?让我们以第一条指令LOAD_CONST为例。中的数字 第一列(2)显示了我们的Python源代码中的行号。的 第二列是字节码的索引,告诉我们 LOAD_CONST指令出现在零位置。第三栏是 指令本身,映射到其可读名称。第四个 列(如果存在)是该指令的参数。第五 列(如果存在)暗示了该参数的含义。
How does the Python Runtime actually work?:
对于Python,它使用解释器而不是编译器。一个 解释器的工作方式与编译器完全相同,只有一个 区别:代替代码生成,它在内存中加载输出 并直接在您的系统上执行。 (有关如何 不同的语言和不同的情况会发生很大的差异 口译员。)
importlib — The implementation of import:
执行reload()时:
Python模块的代码将重新编译,并且模块级代码 重新执行,定义了一组新对象,这些对象绑定到 通过重用最初加载的加载器来加载模块的字典 模块。扩展模块的init函数不称为 第二次。
再次,如果需要编辑此答案以遵循礼节,请告知我。