標記一下:Dive Into Python 內容 html
咱們先偏離一下 HTML 處理的主題, 討論一下 Python 如何處理變量。 Python 有兩個內置的函數,locals和globals, 它們提供了基於 dictionary 的訪問局部和全局變量的方式。 python
還記得locals嗎? 您第一次是在這裏看到的: app
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 程序中的任何一個地方,都存在幾個可用的名字空間。每一個函數都有着自已的名字空間,叫作局部名字空間,它記錄了函數的變量,包括函數的參數和局部定義的變量。每一個模塊擁有它自已的名字空間,叫作全局名字空間,它記錄了模塊的變量,包括函數、類、其它導入的模塊、模塊級的變量和常量。還有就是內置名字空間,任何模塊都可訪問它,它存放着內置的函數和異常。 spa
當一行代碼要使用變量x的值時,Python 會到全部可用的名字空間去查找變量,按照以下順序: .net
若是 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函數來訪問。 code
>>>def foo(arg): ...x = 1 ...print locals() ...>>>foo(7) {'arg': 7, 'x': 1} >>>foo('bar') {'arg': 'bar', 'x': 1}
locals對局部 (函數) 名字空間作了些什麼,globals就對全局 (模塊) 名字空間作了什麼。然而globals更使人興奮,由於一個模塊的名字空間是更使人興奮的。[3] 不只僅是模塊的名字空間包含了模塊級的變量和常量,它還包括了全部在模塊中定義的函數和類。再加上,它包括了任何被導入到模塊中的東西。 htm
回想一下 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.py
SGMLParser = sgmllib.SGMLParser htmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'> BaseHTMLProcessor = __main__.BaseHTMLProcessor __name__ = __main__ ...略...
SGMLParser使用了from module import從sgmllib中被導入。也就是說它被直接導入到咱們的模塊名字空間了,就是這樣。 | |
對比這個和htmlentitydefs, 它是用import被導入的。 也就是說htmlentitydefs模塊自己也在名字空間中, 可是entitydefs變量定義在htmlentitydefs以外。 | |
這個模塊只定義一個類,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
[3] 我沒有說得太多吧。