如何让Python脚本自我修改?

19

如何使 Python 脚本能够修改自身?

简而言之,我想要一个类似于这样的 Python 脚本 (run.py):

a = 0
b = 1
print a + b
# do something here such that the first line of this script reads a = 1

这样下次运行脚本时,它会看起来像这样

a = 1
b = 1
print a + b
# do something here such that the first line of this script reads a = 2

有任何可能性吗?脚本可能使用外部资源,但是只需运行一个run.py文件即可使一切正常工作。

编辑: 可能没有表达清楚,但是脚本应该自己更新,而不是其他文件。当然,一旦允许在脚本旁边放置一个简单的配置文件,这个任务就很容易了。


是的,这是可能的。事实上,有几种方法可以实现这个目标。 - Tomasz Plaskota
1
是的,这是可能的,但为什么呢? - Alex
2
你可以使用 open('run.py','w')... 打开你的脚本并对其进行修改,如果这是你想要的。这就是你想知道的全部吗? - khelwood
1
@khelwood:如果您将原始文件以写入方式打开,那么操作者如何获取要写入的行呢?脚本需要以读取方式打开,然后逐行复制到新文件(以写入方式打开),并更改所需的行。然后重命名该副本。 - cdarke
@cdarke 我恭敬地不同意。 - khelwood
显示剩余9条评论
4个回答

12
对于一个例子(每次运行时更改a的值):
a = 0
b = 1
print(a + b)

with open(__file__, 'r') as f:
    lines = f.read().split('\n')
    val = int(lines[0].split('=')[-1])
    new_line = 'a = {}'.format(val+1)
    new_file = '\n'.join([new_line] + lines[1:])

with open(__file__, 'w') as f:
    f.write(new_file)

6
您所要求的需要在{sys}级别操作文件; 基本上,您需要读取当前文件,修改它,覆盖它并重新加载当前模块。我曾经因为好奇而简短地尝试过这个,但我遇到了文件锁定和文件权限问题。这些问题可能是可以解决的,但我怀疑这不是您想要的。
首先:请意识到通常最好保持代码和数据之间的分离。当然有例外情况,但大多数情况下,您希望使程序可在运行时更改的部分从文件读取其配置,并将更改写入同一文件。
第二:在惯用法中,大多数Python项目使用YAML进行配置
这是一个简单的脚本,使用yaml库从名为'config.yaml'的文件中读取,并在每次程序运行时递增'a'的值:
#!/usr/bin/python
import yaml

config_vals = ""
with open("config.yaml", "r") as cr:
   config_vals = yaml.load(cr)

a = config_vals['a']
b = config_vals['b']
print a + b

config_vals['a'] = a + 1
with open("config.yaml", "w") as cw:
   yaml.dump(config_vals, cw, default_flow_style=True)

运行时输出如下:
$ ./run.py
3 
$ ./run.py
4
$ ./run.py
5 

最初的YAML配置文件如下所示:
a: 1
b: 2

1
实际上,你在第一段描述的正是我想要的东西。 - ImportanceOfBeingErnest

1
创建一个名为a.txt的文件,每行只包含一个字符。
0

然后在你的脚本中,打开那个文件并检索值,然后立即更改它:

with open('a.txt') as f:
    a = int(f.read())
with open('a.txt', 'w') as output:
    output.write(str(a+1))
b = 1
print a+b

在程序第一次运行时,a的值将为0,并且它将更改文件以包含1。在后续运行中,a每次都将增加1。

0

基于Gerrat的代码进行了修改。

#some code here
a = 0
b = 1

print(a + b)

applyLine = 1#apply to wich line(line 1 = 0, line 2 = 1)
with open(__file__, 'r') as f:
  lines = f.read().split('\n')#make each line a str in a list called 'lines'
  val = int(lines[applyLine].split(' = ')[-1])#make an int to get whatever is after ' = ' to applyed line 
  new_line = 'a = {}'.format(val+1)#generate the new line
lines[applyLine] = new_line#update 'lines' to add the new line
write = "\n".join(lines)#create what to rewrite and store it in 'write' as str
with open(__file__, 'w') as f:
  f.write(write)#update the code

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Michael Katt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接