| 導航:起始頁 > Dive Into Python > HTML 處理 > locals 和 globals | << >> | ||||
深入 Python :Dive Into Python 中文版Python 從新手到專家 [Dip_5.4b_CPyUG_Release] |
|||||
我們先偏離一下 HTML 處理的主題,討論一下 Python 如何處理變量。Python 有兩個內置的函數,locals 和 globals,它們提供了基于 dictionary 的訪問局部和全局變量的方式。
還記得 locals 嗎?您第一次是在這里看到的:
def unknown_starttag(self, tag, attrs):
strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
不,等等,此時您還不能理解 locals 。首先,您需要學習關于命名空間的知識。這很枯燥,但是很重要,因此要要耐心些。
Python 使用叫做名字空間的東西來記錄變量的軌跡。名字空間只是一個 dictionary ,它的鍵字就是變量名,它的值就是那些變量的值。實際上,名字空間可以像 Python 的 dictionary 一樣進行訪問,一會兒我們就會看到。
在一個 Python 程序中的任何一個地方,都存在幾個可用的名字空間。每個函數都有著自已的名字空間,叫做局部名字空間,它記錄了函數的變量,包括函數的參數和局部定義的變量。每個模塊擁有它自已的名字空間,叫做全局名字空間,它記錄了模塊的變量,包括函數、類、其它導入的模塊、模塊級的變量和常量。還有就是內置名字空間,任何模塊均可訪問它,它存放著內置的函數和異常。
當一行代碼要使用變量 x 的值時,Python 會到所有可用的名字空間去查找變量,按照如下順序:
如果 Python 在這些名字空間找不到 x,它將放棄查找并引發一個 NameError 異常,同時傳遞 There is no variable named 'x' 這樣一條信息,回到 例 3.18 “引用未賦值的變量”,您會看到一路上都有這樣的信息。但是您并沒有體會到 Python 在給出這樣的錯誤之前做了多少的努力。
Python 2.2 引入了一種略有不同但重要的改變,它會影響名字空間的搜索順序:嵌套的作用域。
在 Python 2.2 版本之前,當您在一個嵌套函數或 lambda 函數中引用一個變量時,Python 會在當前 (嵌套的或 lambda) 函數的名字空間中搜索,然后在模塊的名字空間。Python 2.2 將只在當前 (嵌套的或 lambda) 函數的名字空間中搜索,然后是在父函數的名字空間 中搜索,接著是模塊的名字空間中搜索。Python 2.1 可 以兩種方式工作,缺省地,按 Python 2.0 的方式工作。但是您可以把下面一行代碼增加到您的模塊頭部,使您的模塊工作起來像 Python 2.2 的方式:from __future__ import nested_scopes |
|
您是否為此而感到困惑?不要灰心!我敢說這一點非常酷。像 Python 中的許多事情一樣,名字空間在運行時直接可以訪問。怎么樣?不錯吧,局部名字空間可以通過內置的 locals 函數來訪問。全局 (模塊級別) 名字空間可以通過內置的 globals 函數來訪問。
>>> def foo(arg):... x = 1 ... print locals() ... >>> foo(7)
{'arg': 7, 'x': 1} >>> foo('bar')
{'arg': 'bar', 'x': 1}
locals 對局部 (函數) 名字空間做了些什么,globals 就對全局 (模塊) 名字空間做了什么。然而 globals 更令人興奮,因為一個模塊的名字空間是更令人興奮的。[6] 模塊的名字空間不僅僅包含了模塊級的變量和常量,還包括了所有在模塊中定義的函數和類。除此以外,它還包括了任何被導入到模塊中的東西。
回想一下 from module import 和 import module 之間的不同。使用 import module,模塊自身被導入,但是它保持著自已的名字空間,這就是為什么您需要使用模塊名來訪問它的函數或屬性:module.function 的原因。但是使用 from module import,實際上是從另一個模塊中將指定的函數和屬性導入到您自己的名字空間,這就是為什么您可以直接訪問它們卻不需要引用它們所來源的模塊。使用 globals 函數,您會真切地看到這一切的發生。
看看下面列出的在文件 BaseHTMLProcessor.py 尾部的代碼塊:
if __name__ == "__main__": for k, v in globals().items():print k, "=", v
| 不要被嚇壞了,想想以前您已經全部都看到過了。globals 函數返回一個 dictionary,我們使用 items 方法和多變量賦值來遍歷 dictionary。在這里唯一的新東西就是 globals 函數。 |
現在從命令行運行這個腳本,會得到下面的輸出 (注意您的輸出可能有略微的不同,這依賴于您的系統平臺和所安裝的 Python 版本):
c:\docbook\dip\py> python BaseHTMLProcessor.pySGMLParser = sgmllib.SGMLParserhtmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'>
BaseHTMLProcessor = __main__.BaseHTMLProcessor
__name__ = __main__
... rest of output omitted for brevity...
| 我們使用了 from module import 把 SGMLParser 從 sgmllib 中導入。也就是說它被直接導入到我們的模塊名字空間了,就是這樣。 | |
| 把上面的例子和 htmlentitydefs 對比一下,它是用 import 被導入的。也就是說 htmlentitydefs 模塊本身被導入了名字空間,但是定義在 htmlentitydefs 之中的 entitydefs 變量卻沒有。 | |
| 這個模塊只定義一個類,BaseHTMLProcessor,不錯。注意這兒的值就是類本身,不是一個特別的類實例。 | |
| 記得 if __name__ 技巧嗎?當運行一個模塊時 (相對于從另外一個模塊中導入而言),內置的 __name__ 是一個特殊值 __main__。因為我們是把這個模塊當作腳本從命令來運行的,故 __name__ 值為 __main__,這就是為什么我們這段簡單地打印 globals 的代碼可以執行的原因。 |
| 使用 locals 和 globals 函數,通過提供變量的字符串名字您可以動態地得到任何變量的值。這種方法提供了這樣的功能:getattr 函數允許您通過提供函數的字符串名來動態地訪問任意的函數。 | |
在 locals 與 globals 之間有另外一個重要的區別,您應該在它困擾您之前就了解它。它無論如何都會困擾您的,但至少您還會記得曾經學習過它。
def foo(arg): x = 1 print locals()locals()["x"] = 2
print "x=",x
z = 7 print "z=",z foo(3) globals()["z"] = 8
print "z=",z
![]()
[6] 我沒有說得太多吧。
<< BaseHTMLProcessor.py 介紹 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
基于 dictionary 的字符串格式化 >> |