2013-04-23 82 views
1

所以,我的代码是这样的:强制功能参数是一个字符串

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

我对我想要的一个好主意:为了让用户更容易,我可以在评估之前解析表达式,并在解析过程中添加引号。用这种方式,用户不需要输入恼人的引号。 (我忘了说表达式是在GUI的文本条目中输入的) – 2013-04-23 02:06:50

回答

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) 
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'),你的计算器会删除你的作业。

+0

这是'eval'危险的一个很好的具体例子! – SimonT 2013-04-23 01:52:47

2

不,这是不可能的。在解析和评估1.8*x-32之前,您无法拦截Python解释器。

使用eval作为荣耀的计算器是高度可疑的想法。用户可以传入各种恶意的Python代码。 如果您要这样做,您应该尽可能提供一个尽可能小的代码运行环境。传递您自己的全局变量dict,其中只包含允许用户参考的变量。

return eval(s, {'x': x}) 

除了是安全的,这也是一种更好的方式来替代x到表达。

+0

那本字典你通过在所有 – jamylak 2013-04-23 01:55:10

+1

没有提供安全[奈德尔德显示(http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)如果给'的eval(S恶意用户可以运行任意Python函数, {'x':x})',甚至是'eval(s,{'__builtins__':None}'。 – unutbu 2013-04-23 01:56:18

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 

甚至还有一个方便的功能,把字符串转换为sympy对象:

>>> from sympy import sympify, pi 
>>> sympify("x**2 - sin(x)") 
x**2 - sin(x) 
>>> _.subs(x, pi) 
pi**2 

所有不受信任的用户输入保持警告。 [我懒得检查是否evalexecsympify代码路径上使用,因为他们说,每一种武器被加载,即使卸载的。]

相关问题