所以,我的代码是这样的:
def func(s,x):
return eval(s.replace('x',x)
#Example:
>> func('x**2 + 3*x',1)
4
函数func
的第一个参数必须是字符串,因为函数eval
只接受字符串或代码对象。但是,我想在一种计算器中使用此函数,其中用户键入例如2 + sin(2*pi-0.15) + func(1.8*x-32,273)
并获得表达式的答案,并且总是必须在表达式内部之前写入引号func()
。
有没有办法让python理解s
参数总是一个字符串,即使它不在引号之间?
答案 0 :(得分:2)
不,这是不可能的。在解析和评估1.8*x-32
之前,您无法拦截Python解释器。
使用eval
作为美化计算器是一个高度可疑的想法。用户可以传递各种恶意Python代码。 如果你要去做,你应该尽可能少地提供运行代码的环境。传入你自己的全局dict
,其中只包含允许用户使用的变量参考。
return eval(s, {'x': x})
除了更安全之外,这也是将x
替换为表达式的更好方法。
答案 1 :(得分:1)
你可以让它处理两种情况:
def func(s, x=0):
if isinstance(s, basestring):
# x is in the scope, so you don't need to replace the string
return eval(s)
else:
return s
输出:
>>> from math import *
>>> func('2 + sin(2*pi-0.15) + func(1.8*x-32,273)')
-30.1494381324736
>>> func('x**2 + 3*x', 1)
4
警告:eval
可以做的不仅仅是添加数字。我可以输入__import__('os').system('rm /your/homework.doc')
,您的计算器将删除您的作业。
答案 2 :(得分:1)
总之:不,如果我了解你。
在更多内容中,您可以通过将x
作为特殊对象来解决问题。这就是Python数学库SymPy的工作原理。例如:
>>> from sympy import Symbol
>>> x = Symbol('x')
>>> x**2+3*x
x**2 + 3*x
>>> (x**2+3*x).subs(x,1)
4
甚至有一个方便的功能可以将字符串转换为对象:
>>> from sympy import sympify, pi
>>> sympify("x**2 - sin(x)")
x**2 - sin(x)
>>> _.subs(x, pi)
pi**2
有关不受信任的用户输入的所有警告都会保留。 [我太懒了,无法检查eval
代码路径上是否使用exec
或sympify
,正如他们所说,每个武器都被加载,甚至是未加载的武器。
答案 3 :(得分:0)
你可以写一个翻译:
import code
def readfunc(prompt):
raw = input(prompt)
if raw.count(',')!=1:
print('Bad expression: {}'.format(raw))
return ''
s, x = raw.split(',')
return '''x={}; {}'''.format(x, s)
code.interact('Calc 0.1', readfunc)