# Python `eval()`函數
> 原文: [https://thepythonguru.com/python-builtin-functions/eval/](https://thepythonguru.com/python-builtin-functions/eval/)
* * *
于 2020 年 1 月 7 日更新
* * *
`eval()`允許我們執行任意字符串作為 Python 代碼。 它接受源字符串并返回一個對象。
其語法如下:
**語法**:
```py
eval(expr, globals=None, locals=None)
```
| 參數 | 描述 |
| --- | --- |
| `expr`(必填) | `expr`可以是任何有效的 Python 表達式 |
| `globals`(可選) | 執行源時要使用的全局名稱空間。 它必須是字典。 如果未提供,則將使用當前的全局名稱空間。 |
| `locals`(可選) | 執行源時要使用的本地名稱空間。 它可以是任何映射。 如果省略,則默認為`globals`字典。 |
如果同時省略`globals`和`locals`,則使用當前的全局和局部名稱空間。
這是一個演示`eval()`如何工作的示例:
```py
>>>
>>> eval("5 == 5")
True
>>>
>>>
>>> eval("4 < 10")
True
>>>
>>>
>>> eval("8 + 4 - 2 * 3")
6
>>>
>>>
>>> eval("'py ' * 5")
'py py py py py '
>>>
>>>
>>> eval("10 ** 2")
100
>>>
>>>
>>> eval("'hello' + 'py'")
'hellopy'
>>>
```
試試看:
```py
print(eval("5 == 5"))
print(eval("4 < 10"))
print(eval("8 + 4 - 2 * 3"))
print(eval("'py ' * 5"))
print(eval("10 ** 2"))
print(eval("'hello' + 'py'"))
```
`eval()`不僅限于簡單表達。 我們可以執行函數,調用方法,引用變量等。
```py
>>>
>>> eval("abs(-11)")
11
>>>
>>>
>>> eval('"hello".upper()')
'HELLO'
>>>
>>>
>>> import os
>>>
>>>
>>> eval('os.getcwd()') # get current working directory
'/home/thepythonguru'
>>>
>>>
>>> x = 2
>>>
>>> eval("x+4") # x is referenced inside the expression
6
>>>
```
試一試:
```py
print(eval("abs(-11)"))
print(eval('"hello".upper()'))
import os
# get current working directory
print(eval('os.getcwd()'))
x = 2
print(eval("x+4")) # x is referenced inside the expression
```
請注意,`eval()`僅適用于表達式。 嘗試傳遞語句會導致`SyntaxError`。
```py
>>>
>>> eval('a=1') # assignment statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a=1
^
SyntaxError: invalid syntax
>>>
>>>
>>> eval('import re') # import statement
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
import re
^
SyntaxError: invalid syntax
>>>
```
## 邪惡的`eval()`
* * *
您永遠不要直接將不受信任的源傳遞給`eval()`。 由于惡意用戶很容易對您的系統造成破壞。 例如,以下代碼可以用于從系統中刪除所有文件。
```py
>>>
eval('os.system("RM -RF /")') # command is deliberately capitalized
>>>
```
如果`os`模塊在您當前的全局范圍內不可用,則以上代碼將失敗。 但是我們可以通過使用`__import__()`內置函數輕松地避免這種情況。
```py
>>>
>>> eval("__import__('os').system('RM -RF /')") # command is deliberately capitalized
>>>
```
那么有什么方法可以使`eval()`安全嗎?
## 指定命名空間
* * *
`eval()`可選地接受兩個映射,作為要執行的表達式的全局和局部名稱空間。 如果未提供映射,則將使用全局和局部名稱空間的當前值。
這里有些例子:
**示例 1**:
```py
>>>
>>> globals = {
... 'a': 10,
... 'fruits': ['mangoes', 'peaches', 'bananas'],
... }
>>>
>>>
>>> locals = {}
>>>
>>>
>>> eval("str(a) + ' ' + fruits[0]", globals, locals)
'10 mangoes'
>>>
```
**示例 2**:
```py
>>>
>>> eval('abs(-100)', {}, {})
100
>>>
```
即使我們已經將空字典作為全局和本地名稱空間傳遞了,`eval()`仍可以訪問內置函數(即`__builtins__`)。
```py
>>>
>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError',
...
...
'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted'
, 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
>>>
```
要從全局名稱空間中刪除內置函數,請傳遞一個字典,該字典包含一個值為`None`的鍵`__builtins__`。
**示例 3**:
```py
>>>
>>> eval('abs(-100)', {'__builtins__':None}, {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
>>>
```
即使刪除對內置函數的訪問權限后,`eval()`仍然不安全。 考慮以下清單。
```py
>>>
>>> eval("5**98765432111123", {'__builtins__':None}, {})
>>>
```
這個看似簡單的外觀表達式足以使您的 CPU 崩潰。
關鍵要點是僅將`eval()`與受信任的源一起使用。
* * *
* * *
- 初級 Python
- python 入門
- 安裝 Python3
- 運行 python 程序
- 數據類型和變量
- Python 數字
- Python 字符串
- Python 列表
- Python 字典
- Python 元組
- 數據類型轉換
- Python 控制語句
- Python 函數
- Python 循環
- Python 數學函數
- Python 生成隨機數
- Python 文件處理
- Python 對象和類
- Python 運算符重載
- Python 繼承與多態
- Python 異常處理
- Python 模塊
- 高級 Python
- Python *args和**kwargs
- Python 生成器
- Python 正則表達式
- 使用 PIP 在 python 中安裝包
- Python virtualenv指南
- Python 遞歸函數
- __name__ == "__main__"是什么?
- Python Lambda 函數
- Python 字符串格式化
- Python 內置函數和方法
- Python abs()函數
- Python bin()函數
- Python id()函數
- Python map()函數
- Python zip()函數
- Python filter()函數
- Python reduce()函數
- Python sorted()函數
- Python enumerate()函數
- Python reversed()函數
- Python range()函數
- Python sum()函數
- Python max()函數
- Python min()函數
- Python eval()函數
- Python len()函數
- Python ord()函數
- Python chr()函數
- Python any()函數
- Python all()函數
- Python globals()函數
- Python locals()函數
- 數據庫訪問
- 安裝 Python MySQLdb
- 連接到數據庫
- MySQLdb 獲取結果
- 插入行
- 處理錯誤
- 使用fetchone()和fetchmany()獲取記錄
- 常見做法
- Python:如何讀取和寫入文件
- Python:如何讀取和寫入 CSV 文件
- 用 Python 讀寫 JSON
- 用 Python 轉儲對象