gpt4 book ai didi

python - 编译前在运行时预处理函数文本

转载 作者:太空宇宙 更新时间:2023-11-03 19:13:04 25 4
gpt4 key购买 nike

我决定尝试在将函数文本编译为字节码并执行之后对其进行预处理。这仅用于训练。我很难想象它会成为一个令人满意的解决方案。我遇到了一个问题,我想以这种方式解决,但最终找到了更好的方法。所以这只是为了培训和学习新东西,而不是为了真正的使用。

假设我们有一个函数,我们希望在编译之前对其源代码进行相当多的修改:

def f():
1;a()
print('Some statements 1')
1;a()
print('Some statements 2')

例如,用 1; 标记其中的某些行,以便有时对它们进行注释,有时不进行注释。我只是举个例子,功能上的修改可能会有所不同。

为了评论这些行,我创建了一个装饰器。整个代码如下:

from __future__ import print_function


def a():
print('a()')


def comment_1(s):
lines = s.split('\n')
return '\n'.join(line.replace(';','#;',1) if line.strip().startswith('1;') else line for line in lines)


def remove_1(f):
import inspect
source = inspect.getsource(f)
new_source = comment_1(source)
with open('temp.py','w') as file:
file.write(new_source)
from temp import f as f_new
return f_new


def f():
1;a()
print('Some statements 1')
1;a()
print('Some statements 2')


f = remove_1(f) #If decorator @remove is used above f(), inspect.getsource includes @remove inside the code.

f()

我用了inspect.getsourcelines检索函数 f 代码。然后我进行了一些文本处理(在本例中注释行以 1; 开头)。之后,我将其保存到 temp.py 模块,然后将其导入。然后在主模块中修饰一个函数f

应用装饰器时的输出是这样的:

Some statements 1
Some statements 2

不应用时是这样的:

a()
Some statements 1
a()
Some statements 2

我不喜欢的是我必须使用硬盘来加载已编译的函数。是否可以在不将其写入临时模块 temp.py 并从中导入的情况下完成?

第二个问题是关于将装饰器放置在f之上:@replace。当我这样做时,inspect.getsourcelines 使用此装饰器返回 f 文本。我可以手动从 f 的文本中删除。但这是非常危险的,因为可能会应用多个装饰器。因此,我求助于旧式装饰语法 f = remove_1(f),它可以完成这项工作。但是,是否可以使用 @replace 来允许正常的装饰技术?

最佳答案

可以通过在源上调用 exec 语句来避免创建临时文件。 (如果您想对编译进行额外控制,您也可以在 exec 之前显式调用 compile,但 exec 将为您完成编译,所以它是不必要。)正确调用 exec 还有一个额外的好处,即如果函数从其模块的命名空间访问全局变量,该函数将正常工作。

第二个问题描述的问题可以通过在装饰器运行时暂时阻塞它来解决。这样,装饰器与所有其他装饰器一起保留,但没有操作。

这是更新的来源。

from __future__ import print_function

import sys


def a():
print('a()')


def comment_1(s):
lines = s.split('\n')
return '\n'.join(line.replace(';','#;',1) if line.strip().startswith('1;') else line for line in lines)

_blocked = False

def remove_1(f):
global _blocked
if _blocked:
return f
import inspect
source = inspect.getsource(f)
new_source = comment_1(source)
env = sys.modules[f.__module__].__dict__
_blocked = True
try:
exec new_source in env
finally:
_blocked = False
return env[f.__name__]


@remove_1
def f():
1;a()
print('Some statements 1')
1;a()
print('Some statements 2')


f()

def remove_1(f):
import inspect
source = inspect.getsource(f)
new_source = comment_1(source)
env = sys.modules[f.__module__].__dict__.copy()
exec new_source in env
return env[f.__name__]

关于python - 编译前在运行时预处理函数文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12238511/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com