Python是否可以识别对以交互方式运行的文件的更改?

时间:2018-11-29 22:06:38

标签: python interactive

我当时在进行一些故障排除,我很好奇是否可以交互运行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脚本中的模块。我修改了答案,以包括对该问题的引用。

1 个答案:

答案 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函数不称为   第二次。

再次,如果需要编辑此答案以遵循礼节,请告知我。