參考:https://docs.python.org/2/library/functions.html#eval
eval(expression[, globals[, locals]])
The arguments are a Unicode or Latin-1 encoded string and optional globals and locals. If provided, globals must be a dictionary. If provided, locals can be any mapping object.
Changed in version 2.4: formerly locals was required to be a dictionary.
The expression argument is parsed and evaluated as a Python expression (technically speaking, a condition list) using the globalsand locals dictionaries as global and local namespace. If the globals dictionary is present and lacks ‘__builtins__’, the current globals are copied into globals before expression is parsed. This means that expression normally has full access to the standard__builtin__ module and restricted environments are propagated. If the locals dictionary is omitted it defaults to the globalsdictionary. If both dictionaries are omitted, the expression is executed in the environment where eval() is called. The return value is the result of the evaluated expression. Syntax errors are reported as exceptions. Example:
>>> x = 1
>>> print eval('x+1')
2
This function can also be used to execute arbitrary code objects (such as those created by compile()). In this case pass a code object instead of a string. If the code object has been compiled with 'exec' as the mode argument, eval()‘s return value will beNone.
Hints: dynamic execution of statements is supported by the exec statement. Execution of statements from a file is supported by theexecfile() function. The globals() and locals() functions returns the current global and local dictionary, respectively, which may be useful to pass around for use by eval() or execfile().
See ast.literal_eval() for a function that can safely evaluate strings with expressions containing only literals.
1 globals = {'x': 7,
2 'y': 10,
3 'birds': ['Parrot', 'Swallow', 'Albatross']
4 }
5 locals = { }
6
7 # 將上邊的字典作為全局和局部名稱空間
8 a = eval("3*x + 4*y", globals, locals)
轉:表達式與語句 局部變量與全局變量 exec與eval
Python有時需要動態的創造Python代碼,然后將其作為語句執行 或 作為表達式計算。
exec用於執行存儲在字符串中的Python代碼。
1、 語句與表達式的區別:表達式是 某事,語句是 做某事(即告訴計算機做什么)。
比如2*2是4,而print 2*2是打印4。上述兩句代碼在交互式解釋器中執行的結果是一樣的,是因為解釋器總是把所有表達式的值打印出來而已。而在程序中編寫類似2*2這樣的表達式並不會打印顯示什么,編寫print 2*2則會打印4。
語句與表達式的區別在賦值時更明顯,因為語句不是表達式,所以沒有值。如在交互式解釋器中輸入 x=2則不會打印任何東西,立刻出現新的提示符。雖然什么也沒顯現,但是有些東西已經發生變化如x的值現在變為3.這也是語句特性的一般定義:它們改變了事物。比如,賦值語句改變了變量,print語句改變了屏幕顯示的內容。
2、 命名空間(作用域) 全局變量和局部變量
除了全局作用域外,每個函數會都會創建一個新的作用域。變量分為全局變量和局部變量,函數內的變量稱為局部變量只在局部命名空間中起作用。
在函數內部讀取全局變量一般來說不是問題,直接訪問即可。但是,如果局部變量名或者參數的名字與全局變量名相同的話,就不能直接訪問了,因為全局變量被局部變量給屏蔽了。如果確實需要的話,可以使用globals函數獲取被屏蔽的全局變量值。(globals返回全局變量的字典,locals返回局部變量的值)。例如:有一個名為parameter的全局變量,那么在combine(parameter)函數內部訪問全局變量時,因為與參數重名,必須使用globals()['parameter']獲取。代碼如下:
1 |
def combine(parameter): |
2 |
print parameter + globals ()[ 'parameter' ] |
3 |
4 |
#函數調用 |
5 |
parameter = "hello" |
6 |
combine( "berry" ) |
上面講的是再函數內部讀取全局變量的方法,不包括修改。如果要在函數內部修改全局變量,需要告知修改的值是全局變量,因為在函數內部將值賦予一個變量那么變量自動成為局部變量。通過global關鍵字來告訴Python函數內一個需要修改的變量是一個全局變量。代碼如下:
1 |
x = 1 |
2 |
def change_global(n): |
3 |
global x |
4 |
x = x + 1 |
3、執行字符串的語句 exec
如輸入exec "print 'hello'"會打印出hello。(注意:Python 3.0中,exec是一個函數不是一個語句了,因此使用exec('字符串語句')的方式來調用)。exec執行字符串語句存在安全風險,因為exec可能會干擾命名空間,即改變不應該變的變量。例如:
從上面的例子可以看出,exec干擾了命名空間,改變了sqrt的值,使其不是一個函數而變成1了。由此可見,如果對exec不加限制就會存在安全風險。下面是改進措施。
措施:通過增加 in <scope>來實現,其中的<scope>是一個字典,該字典起到放置代碼字符串命名空間的作用。這樣exec執行的代碼只會在<scope>代表的命名空間中起作用。如:
從上面代碼中可以看到,exec語句在scope命名空間中執行,不會影響到現在命名空間的sqrt。scope雖然充當命名空間的作用,但實質仍是一個字典,所以如果想知道scope命名空間中有多少變量時,可通過len(scope)獲得,可通過scope.key()獲得scope命名空間的所有變量。
4、eval 會計算字符串形式的Python表達式,並返回結果的值。
exec語句不會返回任何對象。而eval會返回表達式的值。下面的代碼可以創建一個Python計算器:
1 |
#Python計算器 |
2 |
print eval ( raw_input ( "Please input an arithmetic expression:" )) |
上面代碼解釋,上面代碼中eval內部現在還不是字符串,首先執行raw_input()函數,raw_input()返回你輸入的求值字符串,現在eval函數內部就是求值字符串了,就可以用eval進行字符串的求值了。如輸入:4*5+6,那么raw_input就會返回“4*5+6”,eval求值后為26.
要注意上面代碼與下面代碼的區別:
1 |
print eval ( 'raw_input("Please input an arithmetic expression:")' ) |
在這個代碼中,與Python計算器代碼不同的是,eval函數內直接就是字符串,那么直接對字符串求值,但是字符串中是raw_input表達式,raw_input表達式將用戶的輸入轉換為字符串,所以如果輸入4+5的話會返回"4+5"。注意:raw_input('xxxxx')是一個表達式,表達式的值就是用戶輸入。 可能疑惑的是代碼:exec('raw_input("Please input an arithmetic expression:")')不會報錯,因為ecec也可以用於表達式,只是什么效果也沒達到而已(既不返回值,也沒干事情)。
跟exec一樣,eval也可以使用命名空間。因為盡管表達式一般不會給變量重新賦值,但是表達式可以通過調用函數來達到給全局變量賦值的目的。例如執行下面代碼后,全局變量x的值會被重新賦值為2:
1 |
x = 1 |
2 |
def inc_x(): |
3 |
global x |
4 |
x = x + 1 |
5 |
eval ( "inc_x()" ) |
6 |
print x |
從上面的代碼可以看出eval函數也是不安全的,必須使用命名空間。事實上,可以為eval提供兩個命名空間,一個是全局的,另一個是局部的。全局的必須是字典,局部的可以是任何形式的映射。
exec和eval的命名空間使用代碼(命名空間可以不是空的字典,可以提前為命名空間提供一些值):
1 |
scope = {} |
2 |
scope[ 'x' ] = 1 |
3 |
scope[ 'y' ] = 2 |
4 |
print eval ( 'x+y' ,scope) |
1 |
scope = {} |
2 |
exec "x=2" in scope |
3 |
eval ( "x*x" ,scope) |
參考:http://my.oschina.net/duhaizhang/blog/66048