W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你想在使用范圍內(nèi)執(zhí)行某個(gè)代碼片段,并且希望在執(zhí)行后所有的結(jié)果都不可見(jiàn)。
為了理解這個(gè)問(wèn)題,先試試一個(gè)簡(jiǎn)單場(chǎng)景。首先,在全局命名空間內(nèi)執(zhí)行一個(gè)代碼片段:
>>> a = 13
>>> exec('b = a + 1')
>>> print(b)
14
>>>
然后,再在一個(gè)函數(shù)中執(zhí)行同樣的代碼:
>>> def test():
... a = 13
... exec('b = a + 1')
... print(b)
...
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in test
NameError: global name 'b' is not defined
>>>
可以看出,最后拋出了一個(gè)NameError異常,就跟在?<span class="pre" style="box-sizing: border-box;">exec()</span>
?語(yǔ)句從沒(méi)執(zhí)行過(guò)一樣。 要是你想在后面的計(jì)算中使用到?<span class="pre" style="box-sizing: border-box;">exec()</span>
?執(zhí)行結(jié)果的話就會(huì)有問(wèn)題了。
為了修正這樣的錯(cuò)誤,你需要在調(diào)用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?之前使用?<span class="pre" style="box-sizing: border-box;">locals()</span>
?函數(shù)來(lái)得到一個(gè)局部變量字典。 之后你就能從局部字典中獲取修改過(guò)后的變量值了。例如:
>>> def test():
... a = 13
... loc = locals()
... exec('b = a + 1')
... b = loc['b']
... print(b)
...
>>> test()
14
>>>
實(shí)際上對(duì)于?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的正確使用是比較難的。大多數(shù)情況下當(dāng)你要考慮使用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的時(shí)候, 還有另外更好的解決方案(比如裝飾器、閉包、元類等等)。
然而,如果你仍然要使用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?,本節(jié)列出了一些如何正確使用它的方法。 默認(rèn)情況下,<span class="pre" style="box-sizing: border-box;">exec()</span>
會(huì)在調(diào)用者局部和全局范圍內(nèi)執(zhí)行代碼。然而,在函數(shù)里面, 傳遞給?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的局部范圍是拷貝實(shí)際局部變量組成的一個(gè)字典。 因此,如果?<span class="pre" style="box-sizing: border-box;">exec()</span>
?如果執(zhí)行了修改操作,這種修改后的結(jié)果對(duì)實(shí)際局部變量值是沒(méi)有影響的。 下面是另外一個(gè)演示它的例子:
>>> def test1():
... x = 0
... exec('x += 1')
... print(x)
...
>>> test1()
0
>>>
上面代碼里,當(dāng)你調(diào)用?<span class="pre" style="box-sizing: border-box;">locals()</span>
?獲取局部變量時(shí),你獲得的是傳遞給?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的局部變量的一個(gè)拷貝。 通過(guò)在代碼執(zhí)行后審查這個(gè)字典的值,那就能獲取修改后的值了。下面是一個(gè)演示例子:
>>> def test2():
... x = 0
... loc = locals()
... print('before:', loc)
... exec('x += 1')
... print('after:', loc)
... print('x =', x)
...
>>> test2()
before: {'x': 0}
after: {'loc': {...}, 'x': 1}
x = 0
>>>
仔細(xì)觀察最后一步的輸出,除非你將?<span class="pre" style="box-sizing: border-box;">loc</span>
?中被修改后的值手動(dòng)賦值給x,否則x變量值是不會(huì)變的。
在使用?<span class="pre" style="box-sizing: border-box;">locals()</span>
?的時(shí)候,你需要注意操作順序。每次它被調(diào)用的時(shí)候,?<span class="pre" style="box-sizing: border-box;">locals()</span>
?會(huì)獲取局部變量值中的值并覆蓋字典中相應(yīng)的變量。 請(qǐng)注意觀察下下面這個(gè)試驗(yàn)的輸出結(jié)果:
>>> def test3():
... x = 0
... loc = locals()
... print(loc)
... exec('x += 1')
... print(loc)
... locals()
... print(loc)
...
>>> test3()
{'x': 0}
{'loc': {...}, 'x': 1}
{'loc': {...}, 'x': 0}
>>>
注意最后一次調(diào)用?<span class="pre" style="box-sizing: border-box;">locals()</span>
?的時(shí)候x的值是如何被覆蓋掉的。
作為?<span class="pre" style="box-sizing: border-box;">locals()</span>
?的一個(gè)替代方案,你可以使用你自己的字典,并將它傳遞給?<span class="pre" style="box-sizing: border-box;">exec()</span>
?。例如:
>>> def test4():
... a = 13
... loc = { 'a' : a }
... glb = { }
... exec('b = a + 1', glb, loc)
... b = loc['b']
... print(b)
...
>>> test4()
14
>>>
大部分情況下,這種方式是使用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的最佳實(shí)踐。 你只需要保證全局和局部字典在后面代碼訪問(wèn)時(shí)已經(jīng)被初始化。
還有一點(diǎn),在使用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?之前,你可能需要問(wèn)下自己是否有其他更好的替代方案。 大多數(shù)情況下當(dāng)你要考慮使用?<span class="pre" style="box-sizing: border-box;">exec()</span>
?的時(shí)候, 還有另外更好的解決方案,比如裝飾器、閉包、元類,或其他一些元編程特性。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: