剛好前些天有人提到eval()與exec()這兩個函數,所以就翻了下Python的文檔。這裡就來簡單說一下這兩個函數以及與它們相關的幾個函數,如globals()、locals()和compile():
計算指定表達式的值。也就是說它要執行的Python代碼只能是單個運算表達式(注意eval不支持任意形式的賦值操作),而不能是復雜的代碼邏輯,這一點和lambda表達式比較相似。
eval(expression, globals=None, locals=None)
x = 10
def func():
y = 20
a = eval('x + y')
print('a: ', a)
b = eval('x + y', {'x': 1, 'y': 2})
print('b: ', b)
c = eval('x + y', {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
print('c: ', c)
d = eval('print(x, y)')
print('d: ', d)
func()
輸出結果:
a: 30
b: 3
c: 4
10 20
d: None
對輸出結果的解釋:
動態執行Python代碼。也就是說exec可以執行復雜的Python代碼,而不像eval函數那麼樣只能計算一個表達式的值。
exec(object[, globals[, locals]])
exec函數的返回值永遠為None.
需要說明的是在Python 2中exec不是函數,而是一個內置語句(statement),但是Python 2中有一個execfile()函數。可以理解為Python 3把exec這個statement和execfile()函數的功能夠整合到一個新的exec()函數中去了:
我們把實例1中的eval函數換成exec函數試試:
x = 10
def func():
y = 20
a = exec('x + y')
print('a: ', a)
b = exec('x + y', {'x': 1, 'y': 2})
print('b: ', b)
c = exec('x + y', {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
print('c: ', c)
d = exec('print(x, y)')
print('d: ', d)
func()
輸出結果:
a: None
b: None
c: None
10 20
d: None
因為我們說過了,exec函數的返回值永遠為None。
x = 10
expr = """
z = 30
sum = x + y + z
print(sum)
"""
def func():
y = 20
exec(expr)
exec(expr, {'x': 1, 'y': 2})
exec(expr, {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
func()
輸出結果:
60
33
34
對輸出結果的解釋:
前兩個輸出跟上面解釋的eval函數執行過程一樣,不做過多解釋。關於最後一個數字34,我們可以看出是:x = 1, y = 3是沒有疑問的。關於z為什麼還是30而不是4,這其實也很簡單,我們只需要在理一下代碼執行過程就可以了,其執行過程相當於:
x = 1
y = 2
def func():
y = 3
z = 4
z = 30
sum = x + y + z
print(sum)
func()
先來看下這兩個函數的定義和文檔描述
globals()
描述: Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
翻譯: 返回一個表示當前全局標識符表的字典。這永遠是當前模塊的字典(在一個函數或方法內部,這是指定義該函數或方法的模塊,而不是調用該函數或方法的模塊)
locals()
描述: Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
翻譯: 更新並返回一個表示當前局部標識符表的字典。自由變量在函數內部被調用時,會被locals()函數返回;自由變量在類累不被調用時,不會被locals()函數返回。
注意: locals()返回的字典的內容不應該被改變;如果一定要改變,不應該影響被解釋器使用的局部變量和自由變量。
name = 'Tom'
age = 18
def func(x, y):
sum = x + y
_G = globals()
_L = locals()
print(id(_G), type(_G), _G)
print(id(_L), type(_L), _L)
func(10, 20)
輸出結果:
2131520814344 <class 'dict'> {'__builtins__': <module 'builtins' (built-in)>, 'func': <function func at 0x000001F048C5E048>, '__doc__': None, '__file__': 'C:/Users/wader/PycharmProjects/LearnPython/day04/func5.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F048BF4C50>, '__spec__': None, 'age': 18, '__name__': '__main__', 'name': 'Tom', '__package__': None, '__cached__': None}
2131524302408 <class 'dict'> {'y': 20, 'x': 10, '_G': {'__builtins__': <module 'builtins' (built-in)>, 'func': <function func at 0x000001F048C5E048>, '__doc__': None, '__file__': 'C:/Users/wader/PycharmProjects/LearnPython/day04/func5.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001F048BF4C50>, '__spec__': None, 'age': 18, '__name__': '__main__', 'name': 'Tom', '__package__': None, '__cached__': None}, 'sum': 30}
name = 'Tom'
age = 18
G = globals()
L = locals()
print(id(G), type(G), G)
print(id(L), type(L), L)
輸出結果:
2494347312392 <class 'dict'> {'__file__': 'C:/Users/wader/PycharmProjects/LearnPython/day04/func5.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000244C2E44C50>, 'name': 'Tom', '__spec__': None, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'L': {...}, '__package__': None, '__name__': '__main__', 'G': {...}, '__doc__': None, 'age': 18}
2494347312392 <class 'dict'> {'__file__': 'C:/Users/wader/PycharmProjects/LearnPython/day04/func5.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000244C2E44C50>, 'name': 'Tom', '__spec__': None, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'L': {...}, '__package__': None, '__name__': '__main__', 'G': {...}, '__doc__': None, 'age': 18}
上面打印出的G和L的內存地址是一樣的,說明在模塊級別locals()的返回值和globals()的返回值是相同的。
將source編譯為code對象或AST對象。code對象能夠通過exec()函數來執行或者通過eval()函數進行計算求值。
compile(source, filename, mode[, flags[, dont_inherit]])
s = """
for x in range(10):
print(x, end='')
print()
"""
code_exec = compile(s, '<string>', 'exec')
code_eval = compile('10 + 20', '<string>', 'eval')
code_single = compile('name = input("Input Your Name: ")', '<string>', 'single')
a = exec(code_exec)
b = eval(code_eval)
c = exec(code_single)
d = eval(code_single)
print('a: ', a)
print('b: ', b)
print('c: ', c)
print('name: ', name)
print('d: ', d)
print('name; ', name)
輸出結果:
0123456789
Input Your Name: Tom
Input Your Name: Jerry
a: None
b: 30
c: None
name: Jerry
d: None
name; Jerry
comiple()函數、globals()函數、locals()函數的返回結果可以當作eval()函數與exec()函數的參數使用。
另外,我們可以通過判斷globals()函數的返回值中是否包含某個key來判斷,某個全局變量是否已經存在(被定義)。