Alo*_*hor 4 python self-modifying
我想创建python脚本,它可以使用Python语言服务或使用任何其他方式修改该脚本本身的代码.
例如,跟踪其成功执行计数的脚本
import re
COUNT = 0
def updateCount():
# code to update second line e.g. COUNT = 0
pass
if __name__ == '__main__':
print('This script has run {} times'.format(COUNT))
updateCount()
Run Code Online (Sandbox Code Playgroud)
成功执行此脚本后,代码应更改为
import re
COUNT = 1
def updateCount():
# code to update second line e.g. COUNT = 0
pass
if __name__ == '__main__':
print('This script has run {} times'.format(COUNT))
updateCount()
Run Code Online (Sandbox Code Playgroud)
我想到的简单方法是__file__在写入模式下打开,并使用调节器实验等进行必要的修改.但是这不起作用我得到了例外io.UnsupportedOperation: not readable.即使这种方法有效,也会有很大的风险,因为它会破坏我的整个脚本.所以我正在寻找使用Python语言服务的解决方案.
ddb*_*bug 10
是的,您可以使用语言服务来实现自我修改,如下例:
>>> def foo(): print("original foo")
>>> foo()
original foo
>>> rewrite_txt="def foo(): print('I am new foo')"
>>> newcode=compile(rewrite_text,"",'exec')
>>> eval(newcode)
>>> foo()
I am new foo
Run Code Online (Sandbox Code Playgroud)
因此,通过新的动态生成代码,您可以替换原始源文件中包含的内容,而无需修改文件本身。
python脚本只不过是一个文本文件.因此,您可以将其作为外部文件打开并对其进行读写.(使用__file__变量,您可以获得脚本的确切名称):
def updateCount():
fin = open(__file__, 'r')
code = fin.read()
fin.close()
second_line = code.split('\n')[1]
second_line_parts = second_line.split(' ')
second_line_parts[2] = str(int(second_line_parts[2])+1)
second_line = ' '.join(second_line_parts)
lines = code.split('\n')
lines[1] = second_line
code = '\n'.join(lines)
fout = open(__file__, 'w')
fout.write(code)
fout.close()
Run Code Online (Sandbox Code Playgroud)
@kyriakosSt 的答案有效,但硬编码,分配COUNT必须在第二行,随着时间的推移,当行号由于源被修改为其他内容而改变时,这可能容易出现意外行为。
对于更健壮的解决方案,您可以使用lib2to3解析和更新源代码,通过子类化lib2to3.refactor.RefactoringTool以使用固定器重构代码,该固定器是lib2to3.fixer_base.BaseFix具有模式的子类,用于查找具有模式的表达式语句'COUNT' '=' any,以及transform更新的方法通过增加其整数值来增加最后一个子节点:
from lib2to3 import fixer_base, refactor
COUNT = 0 # this should be incremented every time the script runs
class IncrementCount(fixer_base.BaseFix):
PATTERN = "expr_stmt< 'COUNT' '=' any >"
def transform(self, node, results):
node.children[-1].value = str(int(node.children[-1].value) + 1)
return node
class Refactor(refactor.RefactoringTool):
def __init__(self, fixers):
self._fixers = [cls(None, None) for cls in fixers]
super().__init__(None)
def get_fixers(self):
return self._fixers, []
with open(__file__, 'r+') as file:
source = str(Refactor([IncrementCount]).refactor_string(file.read(), ''))
file.seek(0)
file.write(source)
Run Code Online (Sandbox Code Playgroud)
演示:https : //repl.it/@blhsing/MushyStrangeClosedsource
| 归档时间: |
|
| 查看次数: |
3813 次 |
| 最近记录: |