Question
考慮下面代碼:
- def t(ab=233):
- def t2():print ab
- exec 'print ab'
- # SyntaxError: unqualified exec is not allowed in function 't'
- # because it contains a nested function with free variables
How-To
問題的解決方案參見:In Python, why doesn't exec work in a function with a subfunction?(用戶 Lennart Regebro 的回答)exec 的完整語法參見:6.13 The exec statement. 問題的詳細原因參見:PEP 227 -- Statically Nested Scopes,主要是在 Backwards compatibility 小節的第二個例子。
說一下我對 PEP 227 的理解。python是一門靜態作用域的語言,PEP 227 在 python 2.1 開始引入了一項語言新特性——靜態嵌套作用域。當然也伴隨而來了一些問題。在函數作用域內執行 bare exec 或 import * 的時候,可能會在 local namespace 中創建新的名稱,但由於是動態語句,python 在編譯的時候無法確定這一點。導致的問題就是,python無法在編譯時確定嵌套函數中的名稱綁定。比如下面 inner 函數中的名稱 x,編譯時無法確定是否應該綁定到 global namespace 的名稱 x,因為 exec str 可能會在 local namespace 中也創建名稱 x:
- x = 1
- def outer(str):
- exec str # str = 'x=2'
- def inner():
- print x
編譯時放任不管,運行時再根據實際情況綁定:
編譯時直接強行靜態綁定,忽略動態語句可能的影響
兩種策略各有弊病,所以PEP 227最終決定:
根據這個異常提示信息,也可以反過來總結出拋異常的兩個條件:
要解決這個問題,只需使用 exec ... in ... 語句就可以了。這樣,exec 語句就能保證不會對 local namespace 產生任何影響(修改locals()不會真的影響局部變量),編譯器就能放心的忽略 exec 語句的影響而直接靜態綁定了,這也是為什麼 exec 需要是個關鍵字而不是庫函數。其實這種方法跟上面說的第二種策略是一個意思,只不過把控制權從編譯器交給了開發者。python 3 中對 exec 語義做了一些修改,就不存在這個問題了,所以它不需要再是關鍵字,變成了一個函數。具體還沒了解過。
Supplement
* Python 的 exec、eval 詳解
沒有留言:
張貼留言