在閱讀模塊源碼里, 常常看到 globals() locals() 的使用, 這兩個函數雖然可以從命名中
從外觀上知道不同, 但仍然不明白具體使用方式和實際的意義. 帶着好奇和疑問, 先看看
文檔和搜索相關的博客, 額外還了解到vars() 函數的信息, 在此帶着樣例代碼介紹.
首先參考官方文檔對這三個函數的介紹:
2. Built-in Functions – Python3.5
返回當前全局符號表, 通常在是返回當前模塊下的全局符號表, 比如全局內建的函數,
以及模塊里的全局符號(定義聲明的變量,類, 實例等), 在函數或者類方法中, globals()
返回的模塊符號表是其所在模塊, 而不是調用模塊.
locals() 更新並以字典形式返回當前局部符號表. 自由變量由函數塊的locals() 返回, 而
不會由 class 塊來返回. 需要注意的是, locals() 字典不應該被修改; 在解釋器中對修改行為
可能對 local 值或者自由變量無效.
vars() 返回 __dict__ 屬性, 比如模塊, 類, 實例, 或者其他 帶有 __dict__ 屬性的 object.
比如 模塊和實例擁有可更新的 __dict__ 屬性;然而其他 objects 可能會對 __dict__ 屬性
的寫操作限制(例如 類使用 dictproxy 阻止直接對字典更新).
vars() 如果不傳參數, 那么作用與 locals() 一樣. 需要注意的是, locals 字典只在讀操作
時使用, 因為對 locals 的更新會被忽略.
翻譯完相關文檔解釋后, 用代碼實驗:
#!/usr/bin/env python
# -*- coding: utf-8 -*- # HELLO = 1 # GLOABLS 字典值包含 __builtins__, __doc__等通用的全局內建函數,模塊, # 以及剛才定義的 HELLO GLOABLS = globals() LOCALS = locals() # 此時與 globals() 是等價的!! # globals 和 locals 此時是等價的, GLOBALS 和 LOCALS 其實是指向一個引用 LOCALS['B'] = 1 # VARS 的引用與 GLOABLS LOCALS 一樣, 可用 id() 來證實. VARS = vars() class A(object): # 此時的 locals 是 class 塊的 locals, 擁有 A_LOCALS A_GLOBALS 值 A_LOCALS = locals() # 與 GLOBALS 等價 A_GLOBALS = globals() def__init__(self): self.func_locals = None self.func_globals = None deffunc(self): self.func_locals = locals() self.func_globals = globals() # 即 GLOBALS 值 a = A() a.func() a_vars = vars(a) # 返回實例的 __dict__, 等價於 a_vars = a.__dict__ A_DICT = vars(A) # 返回類的 dictproxy, 不能對其key直接操作賦值. a_vars['func_vars'] = "vars" print(a.func_vars) # "vars"
通過代碼驗證, 反過來理解文檔的解釋. 也明白了之前閱讀他人代碼使用的目的.
有另外一人寫的文章 Python Does What?!? 介紹了 dict 和 vars 的使用.
文中引用一篇 推特吐槽 , 原文是:
Most folks prefer len(s) to s.__len__(), prefer next(it) to it.next(),but forget to use vars(s) rather than s.__dict__
只能說明 vars 這個函數的命名並不是那么直觀, 而且已經有了 dict() 的定義, 也許設計者想出個 vars 命名來使用 233.
其他細節:
* 另外值得一提的是, 直接訪問實例 __dict__ 或者其他屬性, 比用內建函數訪問更高效.
* 在模塊里的全局作用域, 調試時會觀察到 gloabls() (以及等價的 locals())里的 key
是動態變化的. 那么隨着賦值給新變量名后, 字典會動態增加對應的 key.
