python - title中文 - 為什麼使用'eval'是一種不好的做法?




subplot title python (5)

使用eval很弱,不是一個明顯不好的做法。

  1. 它違反了“軟件的基本原則”。 您的來源不是可執行文件的總和。 除了你的來源,還有一些eval的論點,必須清楚地理解。 出於這個原因,這是最後的手段。

  2. 這通常是無意識設計的標誌。 對於動態構建的動態源代碼,很少有很好的理由。 使用委託和其他面向對象設計技術幾乎可以做任何事情。

  3. 它導致相對較慢的即時編譯小部分代碼。 可以通過使用更好的設計模式避免的開銷。

作為一個腳註,在瘋狂的反社會人士手中,它可能無法奏效。 但是,當面對瘋狂的社交用戶或管理員時,最好不要給他們解釋Python。 在真正的邪惡手中,Python可能是一種責任; eval不會增加風險。

我使用以下課程輕鬆存儲我的歌曲數據。

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            exec 'self.%s=None'%(att.lower()) in locals()
    def setDetail(self, key, val):
        if key in self.attsToStore:
            exec 'self.%s=val'%(key.lower()) in locals()

我覺得這比寫出一個if/else塊更具可擴展性。 然而, eval似乎被認為是不好的做法,並且不安全。 如果是這樣,任何人都可以向我解釋為什麼,並告訴我一個更好的方式來定義上面的類?


值得注意的是,針對具體問題,使用eval有幾種選擇:

正如所指出的,最簡單的方法是使用setattr

def __init__(self):
    for name in attsToStore:
        setattr(self, name, None)

一個不太明顯的方法是直接更新對象的__dict__對象。 如果您只想將屬性初始化為None ,那麼這比上述更簡單。 但考慮一下:

def __init__(self, **kwargs):
    for name in self.attsToStore:
       self.__dict__[name] = kwargs.get(name, None)

這允許您將關鍵字參數傳遞給構造函數,例如:

s = Song(name='History', artist='The Verve')

它還允許您更加明確地使用locals() ,例如:

s = Song(**locals())

...並且,如果您確實想將None分配給名稱在locals()的屬性:

s = Song(**dict([(k, None) for k in locals().keys()]))

另一種為屬性列表提供默認值的對象的方法是定義類的__getattr__方法:

def __getattr__(self, name):
    if name in self.attsToStore:
        return None
    raise NameError, name

當以正常方式找不到指定屬性時,將調用此方法。 這種方法比簡單地在構造函數中設置屬性或更新__dict__稍微簡單一些,但它的優點是不會實際創建該屬性,除非它存在,這可以大大減少類的內存使用量。

所有這一切的重點:總的來說,有很多原因可以避免eval執行不受控制的代碼的安全問題,不能調試的代碼的實際問題等等。但更重要的是原因是,一般來說,你不需要使用它。 Python向程序員公開瞭如此多的內部機制,所以你很少真正需要編寫寫代碼的代碼。


在這種情況下,是的。 代替

exec 'self.Foo=val'

你應該使用builtin函數setattr

setattr(self, 'Foo', val)

是的,使用eval是一種不好的做法。 僅舉幾個原因:

  1. 幾乎總是有一個更好的方法來做到這一點
  2. 非常危險和不安全
  3. 使調試變得困難

在你的情況下,你可以使用setattr來代替:

class Song:
    """The class to store the details of each song"""
    attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
    def __init__(self):
        for att in self.attsToStore:
            setattr(self, att.lower(), None)
    def setDetail(self, key, val):
        if key in self.attsToStore:
            setattr(self, key.lower(), val)

編輯:

有些情況下,您必須使用eval或exec。 但他們很少見。 在你的情況下使用eval肯定是一種不好的做法。 我強調不好的做法,因為eval和exec經常用在錯誤的地方。

編輯2:

看起來有些人不同意在OP案中eval是“非常危險和不安全”的。 對於這種特殊情況可能是這樣,但一般情況並非如此。 這個問題是一般的,我列出的理由也適用於一般情況。

編輯3:重新排序點1和4


當使用eval()來處理用戶提供的輸入時,您可以使用戶使用Drop-to-REPL提供如下所示的內容:

"__import__('code').InteractiveConsole(locals=globals()).interact()"

你可能會逃避它,但通常你不想在你的應用程序中執行任意代碼的向量。





eval