2015-09-05 49 views
2

我正在研究一個應用程序,它允許用戶通過輸入一個字符串來定義一個數學函數(就像你在wolfram alpha上看到的那樣)定義的範圍。我使用eval()函數來解釋字符串並填充y值列表(已定義的x值列表)。我只允許eval()訪問一些常見的numpy數學函數和變量名'x'。Python3:與自定義字典不評估數字的eval()

該類允許我爲用戶輸入的每個字符串創建一個對象,並創建兩個列表x和y,用於使用matplotlib進行繪圖。你可以運行這個MWE,看到它處理x罰函數(例如,sin(x),ln(x),3 * x等),並根據需要拋出非數學函數例如'foo'的異常。但是,給它一個數字如'3'或'4.00'會導致eval()在self.y列表中不寫任何內容。您可以在代碼中的各個點上打印self.y的形狀,並且您會看到只要eval()運行(當輸入的字符串是數字時),self.y的形狀就變成()。

#!/usr/bin/env python3 

import numpy as np 
import matplotlib.pyplot as plt 


class functionType(): 

    def __init__(self, funcStr, xlo=0.0, xhi=10.0, res=100): 

     self.x = [] 
     self.y = [] 
     self.xlo = xlo 
     self.xhi = xhi 
     self.res = res 
     self.funcStr = funcStr 
     self.x = np.linspace(self.xlo, self.xhi, self.res) 
     self.safe_dict = {'np':np, 
          'sin':np.sin, 
          'cos':np.cos, 
          'tan':np.tan, 
          'arcsin':np.arcsin, 
          'arccos':np.arccos, 
          'arctan':np.arctan, 
          'sinh':np.sinh, 
          'cosh':np.cosh, 
          'tanh':np.tanh, 
          'arcsinh':np.arcsinh, 
          'arccosh':np.arccosh, 
          'arctanh':np.arctanh, 
          'ln':np.log, 
          'log10':np.log10, 
          'log2':np.log2, 
          'exp':np.exp, 
          'sqrt':np.sqrt, 
          'abs':np.fabs, 
          'x':self.x} 

     try: 
      self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict) 
     except Exception: 
      raise Exception 

    def _reMakeData(self): 

     self.x = np.linspace(self.xlo, self.xhi, self.res) 
     self.safe_dict['x'] = self.x 
     self.y = eval(self.funcStr,{__builtins__:None},self.safe_dict) 

    def setXLow(self, value): 
     self.xlo = value 
     self._reMakeData() 

    def setXHigh(self, value): 
     self.xhi = value 
     self._reMakeData() 

    def setRes(self, value): 
     self.res = value 
     self._reMakeData() 

    def getXLow(self): 
     return self.xlo 

    def getXHigh(self): 
     return self.xhi 

    def getRes(self): 
     return self.res 

    def getData(self): 
     return self.x, self.y 



func = input("gimme a function: ") 
try: 
    plot1 = functionType(func) 
    x, y = plot1.getData() 
    plt.plot(x,y,marker='',color='red') 
    plt.show() 
except Exception as e: 
    print("no good: ",e) 

有沒有人在這裏看到問題?我希望能夠處理想要繪製常量函數的用戶。清楚的是,當我給它一個像4.0這樣的常量時,我​​希望它向self.y中寫入一個列表(它實際上是一維numpy數組,但我們不需要迂腐),長度與self.x相同,填充了4.0的。

這不是一個網絡或服務器應用程序,我是非常清楚的固有EVAL的風險(),所以請沒有手指晃着如何使用它:)

+0

您可以舉一個最簡單的例子來描述預期的功能。 – shanmuga

回答

1

的問題是需要情節的列表y值與x值列表的長度相同。如果你輸入的表達式涉及到x,這可以正常工作,因爲x是一個numpy數組,所以對它進行數學運算將產生一個相同長度的數組。但如果你只是輸入一個數字y被設置爲一個單一的數字,而不是一個數組。

一種可能性是設置y後,檢查它是否是一個numpy的數組,如果沒有,假設它是單數,重複的次數相應的號碼:

if not isinstance(self.y, np.ndarray): 
     self.y = np.repeat(self.y, len(self.x)) 

你的代碼中有幾個其他錯誤和奇怪的事情。在你的字典中,你通過eval,你想使用{'__builtins__': None},報價大約__builtins__。另外,你使用try/except是毫無意義的。做except Exception後立即raise Exception什麼都不做,並隱藏有關什麼樣的異常提出的信息。只要刪除嘗試/除外;如果發生異常,它會傳播,你會看到它是什麼樣的異常。同樣,你的嘗試/除了最後沒有用處。它所做的只是打印一條信息,該信息比沒有發現異常情況下打印的信息要少。

+0

我添加了你的建議,檢查self.y的類類型,並很好地處理了這個問題。感謝您的簡潔和有益的答案。我還糾正了你所看到的其他問題,並將在課堂外捕獲異常情況。親切的謝謝你,鄰居。 – wrkyle