溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python進(jìn)階之路 3.6 使用exec和eval執(zhí)行求值字符串

發(fā)布時(shí)間:2020-07-05 11:15:06 來源:網(wǎng)絡(luò) 閱讀:392 作者:Python進(jìn)階 欄目:編程語言

3.6 使用exec和eval執(zhí)行求值字符串

使用過JavaScript語言的朋友應(yīng)該對(duì)其中的eval函數(shù)印象深刻。沒有接觸過的朋友請看我詳細(xì)的介紹。eval函數(shù)可以將一個(gè)字符串當(dāng)做JavaScript代碼執(zhí)行,也就是說,可以動(dòng)態(tài)執(zhí)行JavaScript代碼。其實(shí)Python語言也有類似的功能,這就是exec函數(shù)。

在終端中按照以下代碼依次輸入:

>>> exec('i = 20')
>>> exec('print(i)')
20
>>> print(i * i)
400

從上面代碼可以看到,調(diào)用了兩次exec函數(shù),該函數(shù)的參數(shù)是字符串類型的值,在本例中是兩句合法的Python語句。exec函數(shù)成功的執(zhí)行了這兩條語句,并輸出了最終的結(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 "<stdin>",line 1,in <module>
TypeError:'int' object is not callable

在上面的代碼中,導(dǎo)入了random模塊中的randint函數(shù),該函數(shù)用于返回一個(gè)隨機(jī)整數(shù)。但在用exec函數(shù)執(zhí)行的Python代碼中,將randint函數(shù)作為一個(gè)變量賦值了,因此在后面的代碼中就無法使用randint函數(shù)隨機(jī)生成整數(shù)了。為了解決這個(gè)問題,可以為exec函數(shù)指定第2個(gè)參數(shù)值,用來表示防止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。

下面我們在講exec函數(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語言中還有另外一個(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語句,然后按Enter鍵執(zhí)行前面輸入的所有Python語句。

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)一樣輸入一條語句就執(zhí)行一條語句,而是輸入完了,在一起執(zhí)行。

回過頭來我們解釋一下什么是字典,字典是集合的一種,通過關(guān)鍵字(key)查找值(value),在Python語言中用一對(duì)花括號(hào)({})定義字典變量,key和value之間用冒號(hào)(:)分隔,多個(gè)key-value之間用逗號(hào)分隔。關(guān)于字典,以后會(huì)更加詳細(xì)的介紹。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI