Python Namespace的基礎觀念

這個主題是關於Python的 Scopes and Namespace 的基本觀念。因為遇到一個bug是因為這個觀念不夠清楚所致,所以紀錄下來。參考以下的程式碼:
count.py
#########################

counter = 0
def increase():
    global counter
    counter += 1
    return counter
count module有一個global變數counter,和一個increase function,執行increase function會讓counter加1。然後有一個名為main的module,如下:
main.py
#########################

import count

print count.counter     # 0
print count.increase()  # 1
print count.counter     # 1
在這個case裡,我都透過count module存取counter變數和increase function。counter在執行increase前後的直都是一致的。接著,來看另一種方式,直接將counter和increase import進來,看看結果是否一致。

from count import counter, increase

print counter     # 0
print increase()  # 1
print counter     # 0
結果發現counter的值並沒有一致,為什麼呢?讓我們來看文件中關於import語法的說明的一段話(The import statement):
...
The first form of import statement binds the module name in the local namespace to the module object, and then goes on to import the next identifier, if any. If the module name is followed by as, the name following as is used as the local name for the module.
...
第一句話的first form指的是語法中第1種寫法,參考如下:
import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*
                | "from" relative_module "import" identifier ["as" name]
                ( "," identifier ["as" name] )*
                | "from" relative_module "import" "(" identifier ["as" name]
                ( "," identifier ["as" name] )* [","] ")"
                | "from" module "import" "*"
Ok, 重點是後面的這句話『binds the module name in the local namespace to the module object』。

所以再回去看第一個case,import count module時,就會以count這個名稱來綁定module物件至main module的local namespace。因此這個case裡,counter和increase function內存取的counter都還存在於count module的local namespace,所以當執行increase時,counter的值是一致的。

第二個case,將counter和increase綁定至main module的local namespace。這時,increase內存取的counter和main module內的counter就不是同一個counter了。因為closure的原理,increase存取的counter是存在於count module所維護的local namespace。

這是如果在後面加一段程式來驗證,會發現counter的值確實有被加1。
import count
print count.counter  # 1

所以,在非必要情況下,應該要儘量減少直接import變數,要存取變數應該由module來存取,如此可減少因為namespace不同而造成的錯覺。當然還是建議讀完官方文件中關於此部份的說明,對Python會有更深入的了解。

留言

熱門文章