2017年9月7日 星期四

[Python 文章收集] Python 的 exec、eval 詳解

Source From Here 
Preface 
Python 動態執行字符串代碼片段(也可以是文件),一般會用到 execeval。 

exec 
The exec statement
exec_stmt: "exec" expression ["in" expression ["," expression]]

注意:exec 是一個語法聲明,不是一個函數.也就是說和 if, for 一樣. 官方文檔對於 exec 的解釋: 
This statement supports dynamic execution of Python code.

exec 的第一個表達式可以是: 
* 代碼字符串
* 文件對象
* 代碼對象
* tuple

前面三種情況差不多,第四種比較特殊最後講. 如果忽略後面的可選表達式, exec 後面代碼將在當前域執行: 
>>> a = 2
>>> exec "a=1"
>>> a
1

如果在表達式之後使用 in 選項指定一個 dict,它將作為 global 和 local 變量作用域: 
>>> a = 10
>>> b = 20
>>> g = {'a':6, 'b':8}
>>> exec "global a; print a,b" in g // g 同時代表 global 與 local 變量作用域
6 8
>>> exec "print a,b" in g
6 8

如果 in 後詳指定兩個表達式,它們將分別用作 global 和 local 變量作用域: 
>>> a = 1
>>> b = 2
>>> c = 3
>>> g = {'a':10, 'b':20}
>>> l = {'a':100, 'b':200, 'c':300}
>>> exec "global a; print a,b,c" in g,l // a 是從 global 作用域
10 200 300
>>> exec "print a,b,c" in g,l // a 是來自 local 作用域
100 200 300

現在說下 tuple 的情況,這也是導致很多人誤以為 exec 是一個函數的原因 (在 3.x 版 exec 已經是函數.)。如果第一個表達式是 tuple
# exec(expr, globals) // 它等效与 exec expr in globals
# exec(expr, globals, locals) // 它等效与 exec expr in globals,locals

eval 
eval 通常用來執行一個字符串表達式,並返回表達式的值。 
eval(expression[, globals[, locals]])

有三個參數,表達式字符串,globals 變量作用域,locals變量作用域。其中第二個和第三個參數是可選的。如果忽略後面兩個參數,則 eval 在當前作用域執行。 
>>> a = 1
>>> eval("a + 1")
2
>>> eval("a = 2")
Traceback (most recent call last):
...

如果指定 globals 參數: 
>>> a = 1
>>> g = {'a':10}
>>> eval("a + 1", g)
11

如果指定 locals 參數: 
>>> a = 10
>>> b = 20
>>> c = 30
>>> g = {'a':1, 'b':2}
>>> l = {'b':200, 'c':300}
>>> eval('a+b+c', g, l) // a 來自 global 作用域; b, c 來自 local 作用域
501

如果要嚴格限制 eval 執行,可以設置 globals 為 __builtins__ (在 Python3+ 為 builtins),這樣這個表達式只可以訪問 __builtin__ module (This module provides direct access to all ‘built-in’ identifiers of Python)。 
>>> globals().keys()
['__builtins__', '__name__', '__doc__', '__package__']
>>> __builtins__

execeval 給我帶來了極大的靈活性,同時也帶來了隱含的危險性,當我們使用它們的時候應該總是記得詳細指定其執行的作用域。 

Supplement 
深入理解 Python 中的 __builtin__ 和 __builtins__ 
What's the deal with __builtins__ vs __builtin__

沒有留言:

張貼留言

[ JS 常見問題 ] Javascript Date output formatting

Source From  Here   Question   I need to  capture the Now() date and time in the YYYY/mm/dd hh:m:sec format . It needs to be in GMT time. Ho...