如何在 Python 中将函数保存为字符串?
How to save a function as string in Python?
给定以下 Python 函数形式的数学函数:
import math
def f(x):
a = x - math.log(x)
b = x + math.log(x)
return a / x + b / math.log(x)
有什么办法可以把这个函数转换成像
这样的字符串
expr = '(x - math.log(x)) / x + (x + math.log(x)) / math.log(x)'
这样当我想调用函数时,我可以简单地使用它
func = lambda x: eval(expr)
print(func(3))
# 4.364513583657809
请注意,我想在原始函数中保留 a
和 b
。实际上,我有更多的中间变量。另外,我知道 sympy
可以完成类似的任务,但我想知道是否可以将函数转换为字符串,因为这样存储效率更高。
有什么建议吗?
您可能正在寻找符号方程求解器!
Sympy 的 lambdify feature 可以为您做到这一点!
>>> fn = sympy.lambdify("x", '(x - log(x)) / x + (x + log(x)) / log(x)')
>>> fn(x=3)
4.364513583657809
注意:这也在内部使用 eval
作为
您的函数在您将其写入文件时已经一个字符串!
如果函数有效Python,你就可以import
它
from myfile import expr
print(expr(3)) # 4.364513583657809
警告永远不要这样做
如果你出于某种原因想要一些非常邪恶的逻辑,你可以直接用inspect.getsource(f)
保存你的函数,然后做这样的事情
>>> fn_body = """def f(x):
... a = x - math.log(x)
... b = x + math.log(x)
... return a / x + b / math.log(x)
... """
>>> eval(f'lambda {fn_body.split("(")[1].split(")")[0]}, _={exec(fn_body)}: {fn_body.split(" ", 1)[-1].split(")")[0]})')(3)
4.364513583657809
它的工作原理是找到调用函数所需的部分,将源评估为参数之一(将其走私到您的命名空间),然后构建一个匿名函数来调用它
进一步注意事项
- 不可远程维护
- 极度脆弱
- 将破坏或与现有的同名函数冲突,具体取决于用途
- 您仍然需要
import math
或任何其他库
- 如果没有更多痛苦,将无法使用默认参数
- 首先调用
eval()
(在创建 lambda
之前)将允许您使用 inspect
来获取签名(.signature()
)并且您可以将它与 re
and/or ast
对于更强大的解析器,但是 1-liner 似乎更令人兴奋
- 设法同时使用
eval()
和 exec()
来额外帮助邪恶
给定以下 Python 函数形式的数学函数:
import math
def f(x):
a = x - math.log(x)
b = x + math.log(x)
return a / x + b / math.log(x)
有什么办法可以把这个函数转换成像
这样的字符串expr = '(x - math.log(x)) / x + (x + math.log(x)) / math.log(x)'
这样当我想调用函数时,我可以简单地使用它
func = lambda x: eval(expr)
print(func(3))
# 4.364513583657809
请注意,我想在原始函数中保留 a
和 b
。实际上,我有更多的中间变量。另外,我知道 sympy
可以完成类似的任务,但我想知道是否可以将函数转换为字符串,因为这样存储效率更高。
有什么建议吗?
您可能正在寻找符号方程求解器!
Sympy 的 lambdify feature 可以为您做到这一点!
>>> fn = sympy.lambdify("x", '(x - log(x)) / x + (x + log(x)) / log(x)')
>>> fn(x=3)
4.364513583657809
注意:这也在内部使用 eval
作为
您的函数在您将其写入文件时已经一个字符串!
如果函数有效Python,你就可以import
它
from myfile import expr
print(expr(3)) # 4.364513583657809
警告永远不要这样做
如果你出于某种原因想要一些非常邪恶的逻辑,你可以直接用inspect.getsource(f)
保存你的函数,然后做这样的事情
>>> fn_body = """def f(x):
... a = x - math.log(x)
... b = x + math.log(x)
... return a / x + b / math.log(x)
... """
>>> eval(f'lambda {fn_body.split("(")[1].split(")")[0]}, _={exec(fn_body)}: {fn_body.split(" ", 1)[-1].split(")")[0]})')(3)
4.364513583657809
它的工作原理是找到调用函数所需的部分,将源评估为参数之一(将其走私到您的命名空间),然后构建一个匿名函数来调用它
进一步注意事项
- 不可远程维护
- 极度脆弱
- 将破坏或与现有的同名函数冲突,具体取决于用途
- 您仍然需要
import math
或任何其他库 - 如果没有更多痛苦,将无法使用默认参数
- 首先调用
eval()
(在创建lambda
之前)将允许您使用inspect
来获取签名(.signature()
)并且您可以将它与re
and/orast
对于更强大的解析器,但是 1-liner 似乎更令人兴奋 - 设法同时使用
eval()
和exec()
来额外帮助邪恶