假设我得到一个字符串到eval
temperature*x
我有两组变量 - 简单的变量:
easy_ns = {'x':3, 'y':4}
更难的一个:
harder = ['temperature', 'sumofall']
每个都需要花费大量时间来计算,除非它们是用户提供的表达式的一部分,否则我不想计算它们
E.g。我不想开始检测“温度”,除非我知道它是必需的
我的命名空间中可能有一些“便宜”的变量,但其他我想尽可能推迟计算的变量
如何在评估之前从我的eval字符串中获取变量列表
我知道我可以尝试:eval()除了:我会得到一个:
NameError: name 'temperature' is not defined
是否有提取确切变量名称的pythonic方法?
是否有一种很好的方法来构建懒惰评估的命名空间?
像
这样的东西namespace = {'x':3, 'y':4, 'temperature':lazy_temperature_function}
所以只有在评估我的表达时
res=eval('temperature*x')
是我的惰性温度函数,叫做
当然是 - 我绝对必须使用'eval' - 这就是我发布这些问题的原因
场景是我得到一个带有一组键和值的输入文件,然后用户可以提供一个表达式,他希望我从这些值和一些我不想计算的生成变量的组合计算,除非用户将他们包含在他/她的表达中
答案 0 :(得分:4)
如果你真的需要,你可以使用ast
模块解析代码。 ast.parse
帮助器将为您提供代码的AST树表示:
import ast
code = "temperature*x"
st = ast.parse(code)
for node in ast.walk(st):
if type(node) is ast.Name:
print(node.id)
这将打印:
temperature
x
所以这只提取变量名,就像你说的那样。这似乎是第一步,但我不确定你想要做什么,所以可能采用不同的方法更好。
修改:如果我正确理解您的问题,您希望只有在表达式中出现某些值时才会计算它们吗?我试过这样的事情:
>>> import ast
>>> code = "temperature*x"
>>> x = 5
>>> def lazy_temperature():
return 78
...
>>> names = [node.id for node in ast.walk(ast.parse(code))
if type(node) is ast.Name]
>>> ns = {name: (globals()['lazy_%s' % name])()
if ('lazy_%s' % name) in globals()
else globals()[name]
for name in names}
>>> ns
{'x': 5, 'temperature': 78}
>>> eval(code, ns)
390
除非有一个名为lazy_<name>
的函数,否则此代码段会将值加载到当前作用域之外。如果<name>
部分出现在表达式中,将调用此函数。
答案 1 :(得分:0)
你可以把它变成一个lambda函数,只需在需要的时候执行它,就这样:
a = lambda : 5*temperature
a()
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "<stdin>", line 1, in <lambda>
> NameError: global name 'temperature' is not defined
temperature = 100
a()
> 500
这样,除非你有意识地想要,否则你不会寻找执行。
但是,如果温度存在,您还可以确保仅输入lambda函数。你可以通过在文件开头为None
指定温度来做到这一点,如果需要,只需输入lambda:
temperature = None
if temperature:
a()
# do something else
如果您不想使用parens`fn() - 您还可以使用属性构建一个类来执行此操作。
class a(object):
@property
def temp_calc(self):
return self.temp*5
通过这种方式,您可以执行以下操作:
temp_obj = a()
temp_obj.temp_calc
这将返回错误,因为您没有&#34; temp&#34;属性。但是如果需要,你可以分配它:
temp_obj.temp = 5
temp_obj.temp_calc
> 25
这里有很多选择,我希望这些帮助。