函式的傳入參數只存在於 local scope(也可以叫做 function scope),有別於 global scope。
在函式內指定的變數為 local scope,在函式外指定的變數為 global scope,這裡的指定就是 =。
global_var = 'Neil' def aFunction(local_var): another_local_var = 'Egg' print(global_var) # Neil print(local_var) # Emma print(another_local_var) # Egg print(global_var) # Neil aFunction('Emma') print(local_var) # NameError: name 'local_var' is not defined print(another_local_var) # NameError: name 'another_local_var' is not definedlocal scope 變數在函式結束後就消失了,不能再呼叫。
在函式裡(local scope)可以使用 global scope 變數,但不能對 global scope 變數改值(使用 = ),除非使用 global 語句。
global_var = 'Neil' def aFunction(): print(global_var) # Neil global_var = 'Egg' # UnboundLocalError: local variable 'global_var' referenced before assignment aFunction()在函式裡直接修改 global scope 變數的值會報錯,這個錯誤(UnboundLocalError: local variable 'global_var' referenced before assignment)很奇怪,呆會再解釋。
global_var = 'Neil' def aFunction(): global global_var print(global_var) # Neil global_var = 'Egg' # 沒報錯了 print(global_var) # Egg aFunction()在函式裡先用 global 語句標注 global scope 變數,之後就可以在函式裡修改 global scope 變數的值。
接下來回頭解釋沒有使用 global 語句的那個奇怪訊息(UnboundLocalError: local variable 'global_var' referenced before assignment)。
先看一段類似的程式,沒有用 global 語句,也沒有先呼叫 global scope 變數,而是先修改 global scope 變數的值再印出來,這次就沒有報錯,奇怪吧?
global_var = 'Neil' def aFunction(): global_var = 'Egg' print(global_var) # Egg aFunction()了解原因後就不會覺得太奇怪。
首先,Python 允許 local scope 裡使用與 global scope「同名」的變數,這就解釋前一個範例為什麼不會報錯,因為函式裡的 global_var 根本就一個 local scope 變數,和函式外的 global_var 一點關係也沒有。
雖然說 Python 允許 local scope 裡使用與 global scope「同名」的變數,但不建議這麼做,因為這樣只會找自己麻煩。
再來就是 Python 有一個非常奇怪的行為,至少對一個 Java PG 來說是很不習慣的,那就是函式裡的任何變數指定,只要該變數沒有使用 global 語句,一律視為 local scope 變數,不管它出現的位置為何。
最後一句話最重要,Python 在一個函式裡會先去掃出所有的變數指定,先確認它是 local scope 或 global scope,然後才開始執行函式內容。
global_var = 'Neil' def aFunction(): print(global_var) # Neil global_var = 'Egg' # UnboundLocalError: local variable 'global_var' referenced before assignment aFunction()以上面函式為例,Python 先找到 global_var = 'Egg',然後沒看到 global global_var,所以認定 global_var 是 local scope 變數,最後在執行函式內容時,於第一行遇到 print(global_var) 就會報錯說:等等,你不可以在指定變數前就呼叫它。
這就是那個奇怪的錯誤訊息在說的事,UnboundLocalError: local variable 'global_var' referenced before assignment,不可以在指定變數前就呼叫它。
因此如果要在函式裡使用 global scope 變數,那就在函式一開始的地方就使用 global 語句。
另外也不能使用不同 local scope 間的變數,例如在 A 函式裡呼叫了 B 函式,在 B 函式裡不能使用 A 函式的 local scope 變數,也就是 A 函式不會變成 B 函式的 global 環境,global 永遠只有一個,就是主程式所在的位置。
以下列出幾點識別變數 scope 的準則:
- 在函式外指定的變數,為 global scope
- 在函式內使用 global 語句的變數,為 global scope
- 在函式內指定但沒有使用 global 語句的變數,為 local scope
- 在函式內呼叫但沒有指定的變數,為 global scope
可以再簡化成:在函式內使用 global scope 變數時,global 語句只有在修改(重新指定)才需要,只有呼叫時不需要。
一個變數的 scope 只會屬於一種,local 或 global,不會同時兼具兩種 scope,不能在函式先把變數當成 global scope,事後又想轉成 local scope,或者想把 local scope 變數再透過 global 語句轉成 global scope 變數。
最後,有一條簡單的原則可以避免這個複雜的 scope 邏輯,就是「不要在函式裡直接呼叫 global scope 變數,改以參數的方式傳入,若有需要,再用 return 的方式回傳」。
這就是 Utility Function 的設計概念,Python 的內建函式都是這麼做的。
---
---
---
沒有留言:
張貼留言