scn*_*erd 5 python inline abstract-syntax-tree compiler-optimization
在C程序中,内联函数是一种相当直观的优化.如果内联函数的主体足够小,则最终将跳转保存到函数和创建堆栈帧,并将返回值存储在函数结果存储的任何位置,跳转到内联函数的"body"的末尾"而不是长跳到返回指针.
我有兴趣在Python中做同样的事情,将两个python函数转换为另一个有效的python函数,其中第一个被"内联"到第二个.对此的理想解决方案可能如下所示:
def g(x):
return x ** 2
def f(y):
return g(y + 3)
# ... Becomes ...
def inlined_f(y):
return (y + 3) ** 2
Run Code Online (Sandbox Code Playgroud)
显然,在一种像Python一样动态的语言中,自动执行这一点并非易事.我提出的最好的通用解决方案是使用dict捕获传递给函数的参数,将函数体包装在一个迭代for循环中,用于break跳转到函数的末尾,并将参数的使用替换为索引参数字典.结果如下所示:
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
_g['return'] = _g['x'] ** 2
break
_g_return = _g.get('return', None)
del _g
return _g_return
Run Code Online (Sandbox Code Playgroud)
我不在乎它是否丑陋,但我确实关心它不支持循环内的返回.例如:
def g(x):
for i in range(x + 1):
if i == x:
return i ** 2
print("Woops, you shouldn't get here")
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
for _g['i'] in range(_g['x'] + 1):
if _g['i'] == _g['x']:
_g['return'] _g['i'] ** 2
break # <-- Doesn't exit function, just innermost loop
print("Woops, you shouldn't get here")
_g_return = _g.get('return', None)
del _g
return _g_return
Run Code Online (Sandbox Code Playgroud)
我可以采取什么方法来避免需要使用break"跳出"内联函数体的问题?我也可以采用一种更好的通用方法,将一个Python函数内联到另一个函数中.
作为参考,我正在使用AST(抽象语法树)级别,因此使用解析的Python代码; 很明显,除了字面值之外,我不知道在执行这种转换时会有什么价值或类型.生成的内联函数必须与原始函数的行为相同,并且必须支持调用函数时通常可用的所有功能.这在Python中甚至可能吗?
编辑:我应该澄清,因为我使用标签"优化",我实际上并没有对性能提升感兴趣.生成的代码不需要更快,它只是不能调用内联函数,同时仍然表现相同.您可以假设这两个函数的源代码都可用作有效的Python.
与 a 最接近的模拟return可能是引发 an Exception,它将从嵌套循环中弹出到“内联函数”的顶部。
class ReturnException(Exception):
pass
g = dict(x=y + 3)
try:
for j in some_loop:
for _g['i'] in range(_g['x'] + 1):
if _g['i'] == _g['x']:
raise ReturnException(_g['i'] ** 2)
except ReturnException as e:
_g['return'] = e.message
else:
_g['return'] = None
Run Code Online (Sandbox Code Playgroud)
我不知道与异常相关的开销有多少,或者这是否比简单地调用函数更快。
| 归档时间: |
|
| 查看次数: |
1089 次 |
| 最近记录: |