2013-05-03 48 views
0

normaly我可以使用eval這樣。現在我發現了一些代碼,其中有人想使用eval,但是使用更通用的對象而不是字典。 在下面的代碼是什麼basicly這個人做的:評估和演示不僅字典

class myStuff(object): 
    def __init__(self): 
     self.color = "green" 

class Dummy(dict): 
    def __init__(self, node): 
     dict.__init__(self) 
     self.node = node 

    def __getitem__(self, key): 
     return(getattr(self.node, key)) 


node=myStuff() 
new_dict = Dummy(node) 
print eval("color=='green'",new_dict) 

我現在想知道 - 怎麼上面的代碼的開發者知道,EVAL使用方法__getitem__上new_dict的顏色?我發現的文件和蟒蛇幫助功能,但我發現couln't一步一步的文檔的方法(或實際的代碼),這樣我就永遠不會來了個主意,只是什麼做上面的代碼呢。或者是不好用上面的方法,因爲沒有人真正知道如何eval方法已經實現,因此代碼能想出在未來的一些奇怪的錯誤?

編輯:這是爲什麼在程序中使用eval:想象一下,你有像列表mylist myStuff的20個對象,你想通過黃色過濾它們,然後可以簡單地調用[n爲mylist中的n eval(query,Dummy(n)] with`query =「color =='yellow'」。我不是專家,但我只是想知道這種方法是否會導致問題。

+7

你爲什麼這樣使用'eval'?剛纔'd ['color'] =='green''有什麼問題? – Blender 2013-05-03 21:25:58

+0

想知道* eval *如何工作(即在命名空間中執行評估,可以使用\ _ \ _ getitem \ _ \ _進行任意映射)是一個完全合理的問題。該技術是通用的,可以輕鬆實現鏈接計算,例如電子表格中使用的鏈接計算(使用常規字典無法輕鬆完成的計算)。 – 2013-05-03 22:01:51

+2

@RaymondHettinger:是的,我們有理由懷疑'eval'是如何工作的,如果有人寫了OP正在尋找的那種教程,那真的會很酷。但是這並沒有改變這樣一個事實,就像99%的有eval問題的人,OP在這裏不應該使用它。這就是爲什麼總是值得問「爲什麼你想在這裏使用'eval'?」第一。最壞的情況是他們有一個很好的迴應(可以包括「因爲我想了解'eval'」),這使得他們的問題對未來的讀者更有用,對吧? – abarnert 2013-05-03 22:05:30

回答

2

__getitem__的功能是模擬字典或列表(或,更準確地,任何映射或序列)的一種方式。

序列和映射的參考文檔在Data model中,但最好的啓動地點可能是collections.abc模塊以及從那裏的鏈接。

總結的基本概念,當你寫這樣的代碼:

foo[bar] 

Python的將其轉換爲*:

foo.__getitem__(bar) 

沒有什麼錯定義__getitem__模擬dict

而且做起來創建對待自己的屬性字典項目的對象是這樣一個共同的模式,它有一個名字(「attrdict」)。

但是,使用eval幾乎總是做錯了事情。因此,做正確的事情,使eval工作,通常是正確的,因爲你做正確的事情,但錯誤的是,你首先使用eval


你的具體情況,也沒有充分的理由擺在首位使用eval。取而代之的是:

eval("color=='green'",new_dict) 

只是這樣做:

new_dict['color']=='green' 

原因之一Python的新手(尤其是那些誰在舊版本的PHP,TCL,或JavaScript的長大)經常要使用eval是得到他們可以輕鬆傳遞的表達。但是在Python(以及現代PHP和JS)中,函數是一流的值,就像字符串一樣容易傳遞 - 並且與字符串不同,當然它們是可調用的。您可以創建命名函數或lambda函數,或者使用partial,關閉所需的任何局部變量等。

幾乎沒有什麼可以對字符串做任何事情 - 除了當然,打開一個漏洞大的安全漏洞,降低性能,並妨礙調試。

所以,與其是這樣的:

expr = "color=='green'" 
# ... 
eval(expr, new_dict) 

...只是這樣做:

expr = lambda x: x.color=='green' 
# ... 
expr(new_dict) 

在你編輯的問題:

這是爲什麼EVAL是在程序中使用:想象一下,您在列表mylist和您中獲得了20個myStuff對象想要用黃色過濾它們,那麼可以簡單地用`query =「color =='yellow'」來調用[n for mylist if eval(query,Dummy(n)]。

所以,你可能做這樣的事情:

query = "color=={}'.format(color) 
# ... 
[n for n in mylist if eval(query, Dummy(n)] 

但是你可以很容易地做到這一點:當你需要的東西更動態

[n for n in mylist if n.color == color] 

甚至,你可以動態構建函數,甚至比字符串更容易:

query = lambda n: n.color == color 
[n for n in mylist if query(n)] 

事實上,如果你真的想,你甚至可以讓這個完整的功能:

filter(compose(partial(operator.eq, color), attrgetter('color')), mylist) 

但是關於Python的偉大的事情是,你不必去完全功能性或完全必要的,你可以寫在25%或75%之間,或者是最容易閱讀和書寫的東西。


同時:

或者是不好用上面的方法,因爲沒有人真正知道如何eval方法已經實現,因此代碼能想出在未來的一些奇怪的錯誤?

不,這差不多從來沒有一個問題。

首先,documentation for eval通常足以準確預測它將執行的操作,所有Python實現必須遵循該文檔。

在極少數情況下,您需要知道更多,所有主要實現都是開源的,因此您可以閱讀代碼。例如,你可以在網上瀏覽here CPython的3.3碼**


*這不完全準確。真正的代碼實際上在類中查找__getitem__而不是對象(在舊版和新版的2.x版中略有不同),並且處理來自C模塊/ Java包的擴展類型/任何適合您的Python實現的交易類型,交易與切片(2.x與3.x不同),等等。但這是基本的想法。

**的eval代碼已逐步多年來重構,所以在這一點上,你可以非常使用ast模塊和朋友,或者使用C幾行重新實現純Python幾行evalPyEval*函數,因此很難指出您確切的代碼行,而不知道您關心的是哪個實現和版本。

+0

嘿,謝謝你的回覆。我的例子使用eval沒有太大意義。我只是想激勵代碼。我在編輯部分編寫了代碼中實際使用eval的地方。你會不會說它不推薦在那裏使用它? – Adam 2013-05-03 21:51:17

+0

是的,它仍然不被推薦。讓我編輯答案來解釋如何做到這一點。 – abarnert 2013-05-03 21:56:13

2

__getitem__是什麼dict s通過覆蓋__getitem__並使其返回self.node的屬性,您基本上將node轉換爲字典。

更簡單的方法是使用__dict__屬性,它做同樣的事情:

print eval("color=='green'", node.__dict__) 

不過說真的,不要用這個。請。 eval()很少爲工作的工具,這是的,你不需要使用eval一個完美的實例。

+0

感謝您的回覆。其實我現在正在github上完成一個完成的程序,我試着理解我之前的人在代碼中做了什麼(他現在已經走了,但至少我可以通過電話聯繫他)。想象一下,你在列表'mylist'中得到了20個myStuff對象,並且你想用黃色過濾它們,那麼如果eval(query,Dummy(n)]'或者你就可以簡單地調用'[n for mylist用'query =「color =='yellow'」說出'[n for m inist if nval(query,n .__ dict__]''。我不是專家,但我只想知道這種方法是否會導致問題。爲什麼你會建議不要使用它? – Adam 2013-05-03 21:44:24