2016-06-09 36 views
1

在我被'eval是邪惡'的人羣擊斃之前,在這種情況下這是一個必要的罪惡,我無法改變它。 Eval有它的用途,並且在嚴格控制的環境中它非常強大。Dash in dictionary key and eval

但是,我有一個問題沒有明顯的解決方案,我希望在盒子外面思考。

>>> mydict = {"a-b": "woohoo"} 
>>> mydict["a-b"] 
'woohoo' 
>>> eval('mydict["a-b"]') 
'woohoo' 
>>> eval('a-b', mydict) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1, in <module> 
NameError: name 'a' is not defined 

Unfortuately,最後一種情況是一個我被迫使用,顯然這是行不通的。任何想法如何將表達式評估到我的「全局變量」或「本地」對象中,而不是將它解釋爲 - 作爲負運算符?我的'全局變量'對象中的一些鍵在關鍵字名稱中確實有破折號,這是我無法控制的數據。

下面的評論。

  • 數據來自外部來源。我無法指定或控制數據的格式。
  • 我正在評估的'條款'是從存儲的用戶配置中找到我的。

這是一個較大系統的一部分,用戶可以通過api來推送JSON數據,我們將數據作爲字典在內部處理,然後我們將某些規則應用於數據。規則由管理員從Web界面進行配置。

最終,我需要允許用戶給我一個(可能是複雜的)python一班,並評估它對字典。這不正是eval的目的嗎?如果有更好的方式,我不能口述數據的格式,並且必須允許用戶給我一個字符串以評估? Eval是驚人的,因爲它可以讓用戶做很多很酷的事情,比如使用.get()len(),但顯然它也有不利之處,就像前面提到的無法區分或逃避-一樣。

謝謝!

+3

這裏我們需要更多的上下文。你爲什麼不得不使用'eval'? 'mydict'和''a-b「'從哪裏來?你被允許改變'mydict'的結構嗎?你可以改變這個系統的哪些部分? 'eval'顯然不適合你想要執行的任務。 – user2357112

+2

您是否知道,即使您評估的表達式是非變性的,即使使用像這樣的'eval'變異'mydict'?它在'mydict'中插入一個新的'__builtins__'條目,這可能是非常不可取的。 – user2357112

+0

@ user2357112 1)eval是所有我能找到的工作2)數據來自不受控制的外部來源3)我無法改變結構4)我可以寫任何我喜歡的代碼來完成我更新中陳述的目標題。是的,我很確定eval會改變它,事實上這很好,因爲我們希望在評估中允許儘可能多的python關鍵字。謝謝! – hikaru

回答

1

您正在嘗試在評估期間將字符串「a-b」作爲符號。傳統上,這不起作用,因爲「 - 」(連字符)不是。符號名稱中只能使用[A-Za-z0-9_]()字符。更改連字符強調作品罰款:

>>> mydict = {"a_b": "woohoo"} 
>>> eval('a_b', mydict) 
'woohoo' 
>>> 

然而,在Python3,許多Unicode字符可以在一個符號來使用,其中一些可能是ASCII連字符足夠的替換:

>>> mydict = {"aᐨb": "woohoo"} 
>>> eval('aᐨb', mydict) 
'woohoo' 
>>> 

這裏我用了一個加拿大音節最後的短橫行(儘管顯然是濫用了此代碼的預期目的。)有關此方法的更多信息,請參閱張貼What Unicode symbols are accepted in Python3 variable names?

我需要允許用戶給我一個(可能是複雜的)python一個 班輪和評估它對字典。

如果是這樣的話,不ab應該是字典,它解決了問題的一部分:

>>> mydict = {"a": 34, "b": 13} 
>>> eval('a-b', mydict) 
21 
+0

我可能不清楚。供應商提供的文檔中的實際密鑰格式爲「a-b」,例如「{」item-count「:50}'。所以一個實際的例子是'eval(「item-count」,mydict)',我需要它返回'50'。 – hikaru

1

而不是使用mydict作爲計算表達式的全局變量字典,給給它的用戶訪問爲一個字典:

eval(user_expression, {'data': mydict}) 

然後用戶與像

表達式訪問它
data['a-b'] 

而不是嘗試使用a-b作爲變量名稱,並需要以某種方式中斷Python解析器。如果您可能有JSON數組或其他JSON類型而不是JSON對象,這是非常好的,因爲Python列表不能用作eval的全局變量環境。

如果你想語法更好一點,你可以給用戶的Javascript樣點屬性訪問:

class ItemsAsAttributesDict(dict): 
    def __getattr__(self, name): 
     return self[name] 

# when loading the JSON 
dict = json.loads(json_string, object_hook=ItemsAsAttributesDict) 

然後就像在Javascript中,像data['a']字典條目可以爲data.a訪問,但像data['a-b']這樣的條目仍然需要括號符號。


如果你正在使用mydict爲全局變量快譯通設置,用戶將不得不使用globals()訪問無效的變量名稱鍵:

globals()['a-b'] 

要意識到使用eval會打開令人討厭的攻擊媒介。人們會認爲這些查詢是安全的,他們會從不受信任來源評估查詢,然後有人會問的

__import__('os').system('arbitrary_evil_command') 

的價值,每個人都會恨你。

此外,使用eval將程序綁定到Python語法。您將有一段時間將它移植到任何其他語言,特別是因爲用戶將依賴於列表解析和其他您可能不希望他們使用的Python功能。你甚至可能很難在Python版本之間轉換,或者支持不同的Python版本。