使用過JavaScript語(yǔ)言的朋友應(yīng)該對(duì)其中的eval函數(shù)印象深刻。沒有接觸過的朋友請(qǐng)看我詳細(xì)的介紹。eval函數(shù)可以將一個(gè)字符串當(dāng)做JavaScript代碼執(zhí)行,也就是說,可以動(dòng)態(tài)執(zhí)行JavaScript代碼。其實(shí)Python語(yǔ)言也有類似的功能,這就是exec函數(shù)。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了互助免費(fèi)建站歡迎大家使用!
在終端中按照以下代碼依次輸入:
>>> exec('i = 20')
>>> exec('print(i)')
20
>>> print(i * i)
400
從上面代碼可以看到,調(diào)用了兩次exec函數(shù),該函數(shù)的參數(shù)是字符串類型的值,在本例中是兩句合法的Python語(yǔ)句。exec函數(shù)成功的執(zhí)行了這兩條語(yǔ)句,并輸出了最終的結(jié)果。從這點(diǎn)可以看出,exec函數(shù)不僅可以執(zhí)行Python代碼,還可以共享上下文,而且通過exec函數(shù)執(zhí)行Python代碼,與直接通過Python解釋器執(zhí)行是完全一樣的。上下文都是共享的,所以最后用print函數(shù)輸出i * i 的結(jié)果是400。
不過在使用exec函數(shù)執(zhí)行Python代碼的時(shí)候需要注意,盡可能不要讓用戶可以在全局作用域下執(zhí)行Python代碼,否則可能會(huì)與命名空間沖突。
例如下面代碼:
>>> from random import randint
>>> randint(1,20)
15
>>> exec('randint = 30')
>>> randint(1,20)
Traceback (most recent call lase):
File "",line 1,in
TypeError:'int' object is not callable
在上面的代碼中,導(dǎo)入了random模塊中的randint函數(shù),該函數(shù)用于返回一個(gè)隨機(jī)整數(shù)。但在用exec函數(shù)執(zhí)行的Python代碼中,將randint函數(shù)作為一個(gè)變量賦值了,因此在后面的代碼中就無(wú)法使用randint函數(shù)隨機(jī)生成整數(shù)了。為了解決這個(gè)問題,可以為exec函數(shù)指定第2個(gè)參數(shù)值,用來(lái)表示防止exec函數(shù)執(zhí)行的Python代碼的作用域(字典)。
>>> from random import randint
>>> randint(1,20)
9
>>> scope == {}
>>> exec('randint = 30',scope)
>>> randint(1,20)
19
>>> scope.keys()
dict_keys(['_builtins_','randint'])
在上面代碼中,為exec函數(shù)指定了第2個(gè)參數(shù)(一個(gè)字典類型的變量)。這時(shí)randint = 30 設(shè)置的randint變量實(shí)際上屬于scope,而不是全局的,所以與randint函數(shù)并沒有沖突。使用scope.keys函數(shù)查看scope中的key,會(huì)看到randint。
下面我們?cè)谥vexec函數(shù)中的第3個(gè)參數(shù),用于為exec函數(shù)要指定的Python代碼傳遞參數(shù)值。
>>> a = 20
>>> args = {'a':20,'b':30}
>>> scope = {}
>>> exec('print(a + b)',scope,args)
50
在上面的代碼中,exec函數(shù)要執(zhí)行的代碼是print(a + b),這的a和b是兩個(gè)變量,不過這兩個(gè)變量的定義代碼并不是由exec函數(shù)執(zhí)行的,而是在調(diào)用exec函數(shù)前通過args定義的,args是一個(gè)字典,其中有兩個(gè)key:a和b,它們的值分別是20和30。exec會(huì)根據(jù)字典的key對(duì)應(yīng)要執(zhí)行代碼中的同名變量,如果匹配,就會(huì)將字典中相應(yīng)的值傳入要執(zhí)行的代碼。
在Python語(yǔ)言中還有另外一個(gè)函數(shù)eval。這個(gè)函數(shù)余exec函數(shù)類似,只是eval是用于執(zhí)行表達(dá)式的,并返回結(jié)果值。而exec函數(shù)并不會(huì)返回任何值,該函數(shù)只是執(zhí)行Python代碼??梢岳胑val函數(shù)的特性實(shí)現(xiàn)一個(gè)可以計(jì)算表達(dá)式的計(jì)算器。另外,eval也可以像exec函數(shù)一樣,指定scope和為要執(zhí)行的代碼傳遞參數(shù)值。
>>> eval('1 + 2 - 4')
-1
>>> eval('2 * (6 - 4)')
4
>>> scope={'x':20}
>>> args={'y':40}
>>> eval('x + y',scope,args)
60
[例 3.10] 本例將利用exec函數(shù)實(shí)現(xiàn)一個(gè)Python控制臺(tái)??梢栽诳刂婆_(tái)中輸入任意多條Python語(yǔ)句,然后按Enter鍵執(zhí)行前面輸入的所有Python語(yǔ)句。
scope = {}
codes = "" #用于保存輸入的所有代碼
print(">>>",end=" ") #輸出Python控制臺(tái)提示符
while True:
code = input("") #輸入的代碼
if code == "": #如果輸入的是空串,會(huì)執(zhí)行以前輸入的所有Python代碼
exec(codes,scope) #執(zhí)行以前輸入的所有Python代碼
codes = "" #重置codes變量,以便重新輸入Python代碼
print(">>>",end=" ") #繼續(xù)輸出Python控制臺(tái)提示符
continue #忽略后面的代碼
codes += code + "\n" #將輸入的每一行代碼首尾相連,中間換行
輸出結(jié)果:
>>> a = 10
b = 20
c = 30
print(a * (b + c))
500
>>>
這個(gè)Python控制臺(tái)程序與執(zhí)行Python命令進(jìn)入的控制臺(tái)程序類似,只是并不想Python命令進(jìn)入的Python控制臺(tái)一樣輸入一條語(yǔ)句就執(zhí)行一條語(yǔ)句,而是輸入完了,在一起執(zhí)行。
回過頭來(lái)我們解釋一下什么是字典,字典是集合的一種,通過關(guān)鍵字(key)查找值(value),在Python語(yǔ)言中用一對(duì)花括號(hào)({})定義字典變量,key和value之間用冒號(hào)(:)分隔,多個(gè)key-value之間用逗號(hào)分隔。關(guān)于字典,以后會(huì)更加詳細(xì)的介紹。