如果我在运行时修改Python脚本会发生什么?

won*_*ng2 191 python

想象一个需要很长时间才能运行的python脚本,如果我在运行时修改它会发生什么?结果会有所不同吗?

Lix*_*xas 228

没什么,因为python预编译你脚本到PYC文件并从它启动.只有在发生某种异常时 - 您可能会得到错误的解释,因为在行X中可能是启动脚本之前的不同代码

  • 但是,如果你在运行时重新启动,当新的pyc文件覆盖旧的时,会导致已经运行的程序出现问题吗? (55认同)
  • 什么都没发生.我也在一个小测试中检查过它.会发生什么:pyc只是compilate.并且这个compilate被加载到RAM然后执行.因此,总是可以更改程序,重新编译并运行另一个实例,例如在不同的控制台中. (23认同)
  • @Chris我想我知道这里发生了什么.如果修改脚本并在其运行时保存,以及先前版本错误,则在回溯读数中,它将打开文件的当前版本,并使回溯看起来与启动时不同.我曾多次见过这个. (13认同)
  • 不一定是文件. (10认同)
  • @Chris我在一个控制台中启动了我的python脚本实例.当它运行时,我更改了两行代码并在另一个控制台中启动了另一个实例.过了一段时间,我从第一个控制台返回了一个错误,关于我在启动它后改变的两行代码!请帮助 (7认同)
  • @double_j:据我所知,这不可能是由于同时发生的变化。也许您一开始就犯了错误,或者您使用两个脚本访问/修改了相同的资源,这会导致问题。 (2认同)

Nea*_*roo 26

当你运行 python 程序并且解释器启动时,首先发生的事情如下:

  • 模块sys并被builtins初始化
  • 模块__main__被初始化,这是您作为参数提供给解释器的文件;这会导致您的代码执行

当模块初始化时,它的代码就会运行,并在进程中定义类、变量和函数。模块(即主文件)的第一步可能是导入其他模块,这些模块将再次以相同的方式初始化;然后,它们生成的名称空间可供您的模块使用。导入过程的结果部分是内存中的模块(python-)对象。该对象确实具有指向 .py 和 .pyc内容的字段,但不再评估这些字段:模块对象被缓存,并且它们的源永远不会运行两次。因此,之后在磁盘上修改模块不会影响执行。当出于内省目的读取源代码时(例如抛出异常时或通过模块检查) ,它可能会产生影响。

这就是为什么if __name__ == "__main__"在添加不打算在导入模块时运行的代码时进行检查的原因。作为 main 运行该文件与导入该文件等效,只是__name__具有不同的值。


资料来源:


oxe*_*xer 18

这是一个有趣的问题。答案是“这取决于”。

考虑以下代码:

"Example script showing bad things you can do with python."

import os

print('this is a good script')
with open(__file__, 'w') as fdesc:
    fdesc.write('print("this is a bad script")')

import bad
Run Code Online (Sandbox Code Playgroud)

尝试将上面的内容保存为“/tmp/bad.py”,然后执行“cd /tmp”,最后执行“python3 bad.py”,看看会发生什么。

在我的 ubuntu 20 系统上,我看到输出:

this is a good script
this is a bad script
Run Code Online (Sandbox Code Playgroud)

再说一次,你的问题的答案是“这取决于”。如果你没有做任何奇怪的事情,那么脚本就在内存中,你就没事了。但 python 是一种非常动态的语言,因此有多种方法可以修改“脚本”并使其影响输出。

如果您不想做任何时髦的事情,那么可能需要注意的事情之一就是函数内部的导入。

下面是另一个说明这个想法的例子(保存为“/tmp/modify.py”并执行“cd /tmp”,然后运行“python3 modify.py”)。下面定义的函数fiddle模拟您在脚本运行时修改脚本(如果需要,您可以删除 fiddle 函数,time.sleep(300)在倒数第二行添加 a ,然后自己修改文件)。

要点是,由于该show函数是在函数内部而不是在模块顶部进行导入,因此在调用该函数之前导入不会发生。如果您在调用之前修改了脚本show,则将使用您修改后的脚本版本。

如果您在修改正在运行的脚本时发现令人惊讶或意外的行为,我建议您在函数内查找 import 语句。有时有充分的理由去做这类事情,所以你会时不时地在人们的代码以及一些库中看到它。

下面演示了函数内部的导入如何导致奇怪的效果。您可以按原样尝试此操作,而不是注释掉对函数的调用,fiddle以查看在运行时修改脚本的效果。

"Example showing import in a function"

import time

def yell(msg):
    "Yell a msg"
    return f'#{msg}#'
    
def show(msg):
    "Print a message nicely"
    import modify
    print(modify.yell(msg))

def fiddle():
    orig = open(__file__).read()
    with open(__file__, 'w') as fdesc:
        modified = orig.replace('{' + 'msg' + '}', '{msg.upper()}')
        fdesc.write(modified)

fiddle()        
show('What do you think?')
Run Code Online (Sandbox Code Playgroud)