python冷知識之eval()的用法

eval()語法及使用

eval()方法會解析傳入該方法的表達式,而且會在程序中運行解析後的表達式。換句話說,它會將一個字符串解析成代碼來執行。python


STNTAX
eval(expression, GLOBALS=None, LOCALS=None)express

  • expression: 傳入的表達式
  • GLOBALS: 全局方法或者變量的字典
  • LOCALS: 局部方法或者變量的字典

該方法返回表達式執行的結果。
接下來咱們來建立表達式並運行程序來評估該表達式。安全


USAGE函數

user_expr = raw_input("請輸入一個關於變量a的表達式:")
a = int(raw_input("請輸入變量a的值:"))
result = eval(user_expr)
print("result = {}".format(result))

Outputui

請輸入一個關於變量a的表達式: a ** 2 + 1
請輸入變量a的值: 3
result = 10

Security Issue With eval()
假設你導入了os模塊,os模塊提供了一種快捷的方式來操做諸如讀寫文件這樣的操做系統函數。若是你容許用戶使用eval(input())的方式輸入一個值,用戶可能會輸入改變系統文件的命令,甚至會輸入像os.system('rm -rf *')這樣的命令刪除整個系統文件。那麼,在你的代碼中使用eval(input())來檢查用戶可使用的方法和變量不失爲一個好主意,你可使用dir()方法來查看哪些方法和變量是可用的。操作系統

from math import *
print(eval('dir()'))

Outputcode

['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'os', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

在eval()中限制可用方法和變量的使用

大多數狀況下,在expression中使用的方法和變量都不是必須的,甚至會形成安全漏洞。你可能須要限制這些方法和變量的使用,你能夠經過像eval()中傳入globalslocals參數來達到這一目的。orm


1.省略globals和locals參數

若是globalslocals參數都被省略掉,那麼expression會在當前範圍內執行,你可使用下面的方法來檢查可用的方法和變量對象

print(eval(dir()))

2.只傳入globals參數

globals參數和locals參數(字典)分別做用於全局變量和局部變量。若是省略了locals字典,那麼其默認值是globals字典。意思就是,globals字典會同時做用於全局變量和局部變量。rem

你可使用python的內置方法globals()和locals()來分別檢查當前的全局變量和局部變量。

3.傳入一個空字典做爲globals參數
from math import *
print(eval('dir()', {}))

# 下面的代碼會拋出異常
print(eval('sqrt(25)', {}))

Output

['__builtins__']
Traceback (most recent call last):
  File "<string>", line 5, in <module>
    print(eval('sqrt(25)', {}))
  File "<string>", line 1, in <module>
NameError: name 'sqrt' is not defined

若是你傳入一個空字典做爲globals參數,那麼只有__builtins__方法是可用的,即便咱們導入了math模塊,expression也不能訪問任何math模塊提供的方法。


4.指定某些方法可用
from math import *
print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))

Output

['__builtins__', 'pow', 'sqrt']

在這裏,expression只能使用sqrt()、pow()以及__builtins__方法。固然,你也能夠根據你的喜愛來改變可用方法的名字:

from math import *
names = {'square_root': sqrt, 'power': pow}
print(eval('dir()', names))

# 在表達式中使用別名
print(eval('square_root(9)', names))

Output

['__builtins__', 'power', 'square_root']
3.0

在上面的例子中,若是嘗試直接使用sqrt()方法,程序會拋出錯誤。


5.限制built-ins的使用

你能夠經過下面的方法限制expression__builtins__的使用:

eval(expression, {'__builtins__: None})

6.傳入globals和globals參數
from math import *

a = 169
print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))

Output

13.0

在這個例子中,expression能而且只能使用sqrt()方法和變量a,其它的全部方法和變量都不可以使用。


經過globalslocals參數的傳遞來限制eval()的用法可讓你的代碼更加安全,尤爲是在使用用戶經過input()方法給eval()的時候。

有時候,即便限制eval()可以使用的方法和變量也不是安全的,當一個對象和它的的方法是可訪問的,幾乎能夠作任何事,這時候惟一安全的方法就是驗證用戶輸入的有效性。

整理自:

相關文章
相關標籤/搜索