Python 2.1 新特性¶
- 作者:
A.M. Kuchling
引言¶
本文介紹了 Python 2.1 中的新功能。雖然 2.1 中的更改不如 Python 2.0 中的多,但仍然有一些令人驚喜的地方。2.1 是第一個透過使用 Python 增強提案(PEP)指導釋出的版本,因此大多數重大更改都附有相應的 PEP,這些 PEP 提供了更完整的文件和更改的設計原理。本文並不試圖完全記錄新功能,而只是為 Python 程式設計師概述新功能。有關您特別感興趣的任何新功能的更多詳細資訊,請參閱 Python 2.1 文件或特定的 PEP。
Python 開發團隊最近的一個目標是加快新版本的釋出速度,每 6 到 9 個月釋出一個新版本。2.1 是第一個以這種更快的速度釋出的版本,第一個 alpha 版本在 1 月份出現,即 2.0 的最終版本釋出後 3 個月。
Python 2.1 的最終版本於 2001 年 4 月 17 日釋出。
PEP 227:巢狀作用域¶
Python 2.1 中最大的變化是 Python 的作用域規則。在 Python 2.0 中,在任何給定時間,最多有三個名稱空間用於查詢變數名:區域性、模組級和內建名稱空間。這常常讓人感到驚訝,因為它與他們的直覺期望不符。例如,巢狀的遞迴函式定義不起作用
def f():
...
def g(value):
...
return g(value-1) + 1
...
函式 g()
將始終引發 NameError
異常,因為名稱 g
的繫結既不在其區域性名稱空間中,也不在模組級名稱空間中。這在實踐中不是什麼大問題(您多久遞迴定義這樣的內部函式?),但這也會使使用 lambda
表示式變得笨拙,這在實踐中是一個問題。在使用 lambda
的程式碼中,您經常會發現透過將它們作為引數的預設值傳遞來複制區域性變數。
def find(self, name):
"Return list of any entries equal to 'name'"
L = filter(lambda x, name=name: x == name,
self.list_attribute)
return L
結果,以強函式式風格編寫的 Python 程式碼的可讀性大大降低。
Python 2.1 最重要的更改是將靜態作用域新增到語言中以解決此問題。第一個效果是,在上面的示例中,name=name
預設引數現在是不必要的。簡而言之,當在函式內沒有為給定的變數名賦值(透過賦值或 def
,class
或 import
語句)時,對變數的引用將在封閉作用域的區域性名稱空間中查詢。有關規則的更詳細說明以及實現的剖析可以在 PEP 中找到。
此更改可能會為在模組級別以及包含進一步函式定義的函式內使用相同變數名的程式碼造成一些相容性問題。不過,這種情況似乎不太可能,因為這樣的程式碼首先就很難閱讀。
更改的一個副作用是,在某些條件下,from module import *
和 exec
語句在函式作用域內被視為非法。Python 參考手冊一直說 from module import *
僅在模組的頂層合法,但 CPython 直譯器以前從未強制執行此操作。作為巢狀作用域實現的一部分,將 Python 原始碼轉換為位元組碼的編譯器必須生成不同的程式碼來訪問包含作用域中的變數。from module import *
和 exec
使編譯器無法弄清楚這一點,因為它們將名稱新增到編譯時無法知道的區域性名稱空間中。因此,如果函式包含函式定義或具有自由變數的 lambda
表示式,編譯器將透過引發 SyntaxError
異常來標記這一點。
為了使前面的解釋更清楚一點,這裡有一個例子
x = 1
def f():
# The next line is a syntax error
exec 'x=2'
def g():
return x
包含 exec
語句的第 4 行是一個語法錯誤,因為 exec
將定義一個名為 x
的新區域性變數,其值應該由 g()
訪問。
這應該不是什麼限制,因為 exec
在大多數 Python 程式碼中很少使用(並且當它被使用時,通常也是設計不佳的標誌)。
相容性問題導致巢狀作用域被逐步引入;在 Python 2.1 中,它們預設情況下不啟用,但可以透過使用 PEP 236 中描述的 future 語句在模組內啟用。(有關 PEP 236 的進一步討論,請參閱以下部分。)在 Python 2.2 中,巢狀作用域將成為預設設定,並且無法關閉它們,但是使用者將有 2.1 的整個生命週期來修復由於引入它們而導致的任何中斷。
另請參閱
- PEP 227 - 靜態巢狀作用域
由 Jeremy Hylton 編寫和實現。
PEP 236:__future__ 指令¶
對巢狀作用域的反應是廣泛關注在 2.1 版本中破壞程式碼的危險,這足以使 Python 開發人員採取更保守的方法。此方法包括引入一種約定,用於在版本 N 中啟用可選功能,該功能將在版本 N+1 中強制執行。
該語法使用 from...import
語句,使用保留的模組名稱 __future__
。可以透過以下語句啟用巢狀作用域
from __future__ import nested_scopes
雖然它看起來像一個普通的 import
語句,但事實並非如此;對於這種 future 語句的放置位置有嚴格的規則。它們只能位於模組的頂部,並且必須在任何 Python 程式碼或常規 import
語句之前。這是因為此類語句可能會影響 Python 位元組碼編譯器解析程式碼和生成位元組碼的方式,因此它們必須在任何將導致生成位元組碼的語句之前。
另請參閱
- PEP 236 - 回到
__future__
由 Tim Peters 編寫,主要由 Jeremy Hylton 實現。
PEP 207:豐富的比較¶
在早期版本中,Python 對使用者自定義類和擴充套件型別實現比較的支援非常簡單。類可以實現一個 __cmp__()
方法,該方法接收類的兩個例項,如果它們相等則只能返回 0,如果不相等則返回 +1 或 -1;該方法不能引發異常或返回布林值以外的任何內容。Numeric Python 的使用者經常發現這種模型過於薄弱和限制,因為在數值 Python 用於的數字處理程式中,能夠對兩個矩陣執行元素級比較,返回一個包含每個元素給定比較結果的矩陣會更有用。如果兩個矩陣的大小不同,則比較必須能夠引發異常以指示錯誤。
在 Python 2.1 中,為了支援這種需求,添加了豐富的比較。Python 類現在可以分別過載 <
、<=
、>
、>=
、==
和 !=
操作。新的魔術方法名稱是
操作 |
方法名稱 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
(這些魔術方法以相應的 Fortran 運算子 .LT.
、.LE.
等命名。數值程式設計師幾乎肯定對這些名稱非常熟悉,並且會發現它們很容易記住。)
這些魔術方法中的每一個都採用 method(self, other)
的形式,其中 self
將是運算子左側的物件,而 other
將是運算子右側的物件。例如,表示式 A < B
將導致呼叫 A.__lt__(B)
。
這些魔術方法中的每一個都可以返回任何內容:布林值、矩陣、列表或任何其他 Python 物件。或者,如果比較是不可能的、不一致的或沒有意義的,它們可以引發異常。
內建的 cmp(A,B)
函式可以使用豐富的比較機制,現在接受一個可選引數,指定要使用的比較操作;該引數作為字串 "<"
、"<="
、">"
、">="
、"=="
或 "!="
之一給出。如果呼叫時沒有可選的第三個引數,cmp()
將僅返回 -1、0 或 +1,就像在以前版本的 Python 中一樣;否則,它將呼叫適當的方法,並且可以返回任何 Python 物件。
C 程式設計師也會對相應的更改感興趣;型別物件中有一個新的槽 tp_richcmp
和一個用於執行給定豐富比較的 API。我不會在此處介紹 C API,但會請你參考 PEP 207,或參考 2.1 的 C API 文件,以獲取相關函式的完整列表。
另請參閱
- PEP 207 - 豐富的比較
由 Guido van Rossum 編寫,主要基於 David Ascher 早期的工作,並由 Guido van Rossum 實現。
PEP 230:警告框架¶
在其存在的 10 年中,Python 積累了一些過時的模組和功能。很難知道何時可以安全地刪除一個功能,因為沒有辦法知道有多少程式碼使用了它——也許沒有程式依賴該功能,或者也許有很多程式依賴該功能。為了能夠以更結構化的方式刪除舊功能,添加了一個警告框架。當 Python 開發人員想要刪除某個功能時,它將首先在下一個 Python 版本中觸發警告。然後,下一個 Python 版本可以刪除該功能,並且使用者將有一個完整的釋出週期來刪除舊功能的使用。
Python 2.1 添加了警告框架,用於此方案。它添加了一個 warnings
模組,該模組提供了發出警告的功能,以及過濾掉你不希望顯示的警告的功能。第三方模組也可以使用此框架來棄用它們不再希望支援的舊功能。
例如,在 Python 2.1 中,regex
模組已棄用,因此匯入它會導致列印警告
>>> import regex
__main__:1: DeprecationWarning: the regex module
is deprecated; please use the re module
>>>
可以透過呼叫 warnings.warn()
函式發出警告
warnings.warn("feature X no longer supported")
第一個引數是警告訊息;可以使用其他可選引數來指定特定的警告類別。
可以新增過濾器來停用某些警告;可以將正則表示式模式應用於訊息或模組名稱,以抑制警告。例如,你可能有一個使用 regex
模組的程式,並且不想花時間將其轉換為立即使用 re
模組。可以透過呼叫以下程式碼來抑制警告
import warnings
warnings.filterwarnings(action = 'ignore',
message='.*regex module is deprecated',
category=DeprecationWarning,
module = '__main__')
這會新增一個過濾器,該過濾器僅應用於在 __main__
模組中觸發的 DeprecationWarning
類的警告,並且應用正則表示式以僅匹配有關 regex
模組被棄用的訊息,並且將導致忽略此類警告。警告也可以只打印一次,每次執行有問題的程式碼時列印,或轉換為會導致程式停止的異常(當然,除非以通常的方式捕獲異常)。
Python 的 C API 中也添加了用於發出警告的函式;有關詳細資訊,請參閱 PEP 230 或 Python 的 API 文件。
PEP 229:新的構建系統¶
在編譯 Python 時,使用者必須進入並編輯 Modules/Setup
檔案,以啟用各種其他模組;預設集相對較小,並且僅限於在大多數 Unix 平臺上編譯的模組。這意味著在具有更多功能的 Unix 平臺上,尤其是 Linux,Python 安裝通常不包含它們可能包含的所有有用模組。
Python 2.0 添加了 Distutils,一組用於分發和安裝擴充套件的模組。在 Python 2.1 中,Distutils 用於編譯標準庫中的大部分擴充套件模組,自動檢測當前機器上支援哪些模組。希望這將使 Python 安裝更容易且功能更強大。
無需編輯 Modules/Setup
檔案以啟用模組,而是在構建時執行 Python 原始碼分發頂級目錄中的 setup.py
指令碼,並嘗試透過檢查系統上的模組和標頭檔案來發現可以啟用哪些模組。如果在 Modules/Setup
中配置了模組,則 setup.py
指令碼不會嘗試編譯該模組,並且會遵從 Modules/Setup
檔案的內容。這提供了一種指定特定平臺所需的任何奇怪的命令列標誌或庫的方法。
在構建機制的另一個影響深遠的更改中,Neil Schemenauer 重構了事物,因此 Python 現在使用一個非遞迴的 makefile,而不是在頂級目錄和每個 Python/
、Parser/
、Objects/
和 Modules/
子目錄中的 makefile。這使得構建 Python 更快,也使得破解 Makefile 更清晰和更簡單。
另請參閱
- PEP 229 - 使用 Distutils 構建 Python
由 A.M. Kuchling 編寫和實現。
PEP 205:弱引用¶
透過 weakref
模組提供的弱引用是 Python 程式設計師工具箱中一種新的、有用的次要資料型別。
儲存對物件的引用(例如,在字典或列表中)具有使該物件永遠保持活動的副作用。在某些特定情況下,這種行為是不可取的,物件快取是最常見的一種,另一種是樹等資料結構中的迴圈引用。
例如,考慮一個記憶函式,該函式透過將函式的引數及其結果儲存在字典中來快取另一個函式 f(x)
的結果
_cache = {}
def memoize(x):
if _cache.has_key(x):
return _cache[x]
retval = f(x)
# Cache the returned object
_cache[x] = retval
return retval
此版本適用於整數等簡單內容,但它具有副作用;_cache
字典儲存對返回值的引用,因此它們永遠不會被釋放,直到 Python 程序退出並清理為止。這對於整數來說不太明顯,但是如果 f()
返回一個物件或一個佔用大量記憶體的資料結構,這可能會成為問題。
弱引用提供了一種實現快取的方法,它不會使物件在其生命週期結束後仍然存活。如果一個物件只能透過弱引用訪問,則該物件將被釋放,並且弱引用將指示它所引用的物件不再存在。透過呼叫 wr = weakref.ref(obj)
可以建立對物件 obj 的弱引用。透過像呼叫函式一樣呼叫弱引用 wr()
,可以返回被引用的物件。它將返回被引用的物件,如果該物件不再存在,則返回 None
。
這使得編寫 memoize()
函式成為可能,該函式的快取不會透過在快取中儲存弱引用來保持物件的存活狀態。
_cache = {}
def memoize(x):
if _cache.has_key(x):
obj = _cache[x]()
# If weak reference object still exists,
# return it
if obj is not None: return obj
retval = f(x)
# Cache a weak reference
_cache[x] = weakref.ref(retval)
return retval
weakref
模組還允許建立行為類似於弱引用的代理物件——僅由代理物件引用的物件會被釋放——但是,它不需要顯式呼叫來檢索物件,只要物件仍然存在,代理會透明地將所有操作轉發到該物件。如果物件被釋放,則嘗試使用代理將引發 weakref.ReferenceError
異常。
proxy = weakref.proxy(obj)
proxy.attr # Equivalent to obj.attr
proxy.meth() # Equivalent to obj.meth()
del obj
proxy.attr # raises weakref.ReferenceError
另請參閱
- PEP 205 - 弱引用
由 Fred L. Drake, Jr. 編寫和實現。
PEP 232:函式屬性¶
在 Python 2.1 中,函式現在可以附加任意資訊。人們經常使用文件字串來儲存有關函式和方法的資訊,因為 __doc__
屬性是將任何資訊附加到函式的唯一方法。例如,在 Zope Web 應用程式伺服器中,函式透過具有文件字串來標記為可公開訪問,而在 John Aycock 的 SPARK 解析框架中,文件字串儲存要解析的 BNF 語法的一部分。這種過載是不幸的,因為文件字串實際上是為了儲存函式的文件;例如,這意味著您無法正確地記錄 Zope 中用於私有用途的函式。
現在可以使用常規 Python 語法在函式上設定和檢索任意屬性
def f(): pass
f.publish = 1
f.secure = 1
f.grammar = "A ::= B (C D)*"
包含屬性的字典可以作為函式的 __dict__
進行訪問。與類例項的 __dict__
屬性不同,在函式中,您實際上可以為 __dict__
分配一個新的字典,但新值僅限於常規 Python 字典;您不能耍花招並將其設定為 UserDict
例項,或任何其他行為類似於對映的隨機物件。
另請參閱
- PEP 232 - 函式屬性
由 Barry Warsaw 編寫和實現。
PEP 235:在不區分大小寫的平臺上匯入模組¶
某些作業系統具有不區分大小寫的檔案系統,MacOS 和 Windows 是主要的例子;在這些系統上,不可能區分檔名 FILE.PY
和 file.py
,即使它們確實以原始大小寫儲存了檔名(它們也保留大小寫)。
在 Python 2.1 中,import
語句將工作以模擬在不區分大小寫的平臺上的大小寫敏感性。Python 現在預設搜尋第一個區分大小寫的匹配項,如果沒有找到這樣的檔案,則引發 ImportError
,因此 import file
不會匯入名為 FILE.PY
的模組。可以透過在啟動 Python 直譯器之前設定 PYTHONCASEOK
環境變數來請求不區分大小寫的匹配。
PEP 217:互動式顯示鉤子¶
當以互動方式使用 Python 直譯器時,命令的輸出使用內建的 repr()
函式顯示。在 Python 2.1 中,變數 sys.displayhook()
可以設定為可呼叫物件,該物件將代替 repr()
被呼叫。例如,您可以將其設定為特殊的漂亮列印函式
>>> # Create a recursive data structure
... L = [1,2,3]
>>> L.append(L)
>>> L # Show Python's default output
[1, 2, 3, [...]]
>>> # Use pprint.pprint() as the display function
... import sys, pprint
>>> sys.displayhook = pprint.pprint
>>> L
[1, 2, 3, <Recursion on list with id=135143996>]
>>>
另請參閱
- PEP 217 - 互動式使用的顯示鉤子
由 Moshe Zadka 編寫和實現。
PEP 208:新的強制轉換模型¶
在 C 級別進行數值強制轉換的方式已進行了重大修改。這隻會影響 Python C 擴充套件的作者,允許他們在編寫支援數值操作的擴充套件型別時具有更大的靈活性。
擴充套件型別現在可以在其 PyTypeObject
結構中設定型別標誌 Py_TPFLAGS_CHECKTYPES
,以指示它們支援新的強制轉換模型。在這種擴充套件型別中,數值槽函式不能再假定它們將傳遞兩個相同型別的引數;相反,它們可能會傳遞兩個不同型別的引數,然後可以執行自己的內部強制轉換。如果槽函式傳遞了無法處理的型別,則可以透過返回對 Py_NotImplemented
單例值的引用來指示失敗。然後將嘗試其他型別的數值函式,也許它們可以處理該操作;如果其他型別也返回 Py_NotImplemented
,則將引發 TypeError
。用 Python 編寫的數值方法也可以返回 Py_NotImplemented
,從而使直譯器就像該方法不存在一樣(可能引發 TypeError
,也可能嘗試其他物件的數值方法)。
另請參閱
- PEP 208 - 重新設計強制轉換模型
由 Neil Schemenauer 編寫和實現,主要基於 Marc-André Lemburg 早期的工作。閱讀此內容以瞭解數值運算現在如何在 C 級別處理的細節。
PEP 241:Python 包中的元資料¶
Python 使用者常見的抱怨是,沒有一個包含所有現有 Python 模組的目錄。T. Middleton 在 www.vex.net/parnassus/
的 Vaults of Parnassus(於 2009 年 2 月退役,可在網際網路檔案館 Wayback Machine 中找到)是最大的 Python 模組目錄,但在 Vaults 中註冊軟體是可選的,許多人沒有這樣做。
作為解決該問題的第一小步,使用 Distutils sdist 命令打包的 Python 軟體將包含一個名為 PKG-INFO
的檔案,其中包含有關軟體包的資訊,例如其名稱、版本和作者(在編目術語中稱為元資料)。PEP 241 包含 PKG-INFO
檔案中可能存在的欄位的完整列表。隨著人們開始使用 Python 2.1 打包他們的軟體,越來越多的軟體包將包含元資料,從而可以構建自動化編目系統並進行實驗。透過結果經驗,也許可以設計一個真正好的目錄,然後在 Python 2.2 中構建對其的支援。例如,Distutils sdist 和 bdist_* 命令可以支援 upload
選項,該選項會自動將您的軟體包上傳到目錄伺服器。
即使您不使用 Python 2.1,也可以開始建立包含 PKG-INFO
的軟體包,因為 Distutils 的新版本將為早期 Python 版本的使用者釋出。Distutils 的 1.0.2 版本包括 PEP 241 中描述的更改,以及各種錯誤修復和增強功能。它將可從 Distutils SIG 獲得,網址為 https://python.club.tw/community/sigs/current/distutils-sig/。
新的和改進的模組¶
Ka-Ping Yee 貢獻了兩個新模組:
inspect.py
,一個用於獲取即時 Python 程式碼資訊的模組,以及pydoc.py
,一個用於將文件字串互動式轉換為 HTML 或文字的模組。另外,Tools/scripts/pydoc
現在會自動安裝,它使用pydoc.py
來顯示給定 Python 模組、包或類名的文件。例如,pydoc xml.dom
會顯示以下內容Python Library Documentation: package xml.dom in xml NAME xml.dom - W3C Document Object Model implementation for Python. FILE /usr/local/lib/python2.1/xml/dom/__init__.pyc DESCRIPTION The Python mapping of the Document Object Model is documented in the Python Library Reference in the section on the xml.dom package. This package contains the following modules: ...
pydoc
還包含一個基於 Tk 的互動式幫助瀏覽器。pydoc
很快就會讓人上癮;快來試試吧!標準庫中添加了兩個不同的單元測試模組。Tim Peters 貢獻的
doctest
模組提供了一個基於執行文件字串中的嵌入示例並將結果與預期輸出進行比較的測試框架。Steve Purcell 貢獻的 PyUnit 是一個受 JUnit 啟發而來的單元測試框架,JUnit 又是對 Kent Beck 的 Smalltalk 測試框架的改編。有關 PyUnit 的更多資訊,請參閱 https://pyunit.sourceforge.net/。difflib
模組包含一個類SequenceMatcher
,它比較兩個序列並計算將一個序列轉換為另一個序列所需的更改。例如,此模組可用於編寫類似於 Unix diff 程式的工具,實際上,示例程式Tools/scripts/ndiff.py
演示瞭如何編寫這樣的指令碼。Thomas Gellekum 貢獻了
curses.panel
,它是面板庫的包裝器,是 ncurses 和 SYSV curses 的一部分。面板庫為視窗提供了額外的深度功能。視窗可以在深度排序中向上或向下移動,面板庫會計算出面板重疊的位置以及哪些部分可見。自 Python 2.0 以來,PyXML 包已經經歷了幾次釋出,Python 2.1 包含了一個更新版本的
xml
包。一些值得注意的更改包括對 Expat 1.2 及更高版本的支援、Expat 解析器處理 Python 支援的任何編碼檔案的能力,以及對 SAX、DOM 和minidom
模組的各種錯誤修復。Ping 還貢獻了另一個用於處理未捕獲異常的鉤子。
sys.excepthook()
可以設定為可呼叫物件。當異常未被任何try
...except
塊捕獲時,該異常將被傳遞給sys.excepthook()
,然後它可以執行任何操作。在第九屆 Python 大會上,Ping 演示了這個鉤子的一個應用程式:列印一個擴充套件的回溯,該回溯不僅列出堆疊幀,還列出每個幀的函式引數和區域性變數。time
模組中的各種函式,例如asctime()
和localtime()
,需要一個浮點數引數,其中包含自 epoch 以來的時間(以秒為單位)。這些函式最常見的用法是處理當前時間,因此浮點數引數已設定為可選;當未提供值時,將使用當前時間。例如,日誌檔案條目通常需要一個包含當前時間的字串;在 Python 2.1 中,可以使用time.asctime()
,而不是之前需要的冗長的time.asctime(time.localtime(time.time()))
。此更改由 Thomas Wouters 提出並實施。
ftplib
模組現在預設以被動模式檢索檔案,因為被動模式更可能在防火牆後面工作。此請求來自 Debian 錯誤跟蹤系統,因為其他 Debian 包使用ftplib
來檢索檔案,然後在防火牆後面無法工作。認為這不太可能給任何人帶來問題,因為 Netscape 預設使用被動模式,而且很少有人抱怨,但是如果被動模式不適合你的應用程式或網路設定,請在 FTP 物件上呼叫set_pasv(0)
以停用被動模式。Grant Edwards 貢獻的對原始套接字訪問的支援已新增到
socket
模組中。當
pstats
模組作為指令碼執行時,它現在包含一個簡單的互動式統計資訊瀏覽器,用於顯示 Python 程式的計時配置檔案。由 Eric S. Raymond 貢獻。添加了一個新的與實現相關的函式
sys._getframe([depth])
,用於從當前呼叫堆疊返回給定的幀物件。sys._getframe()
返回呼叫堆疊頂部的幀;如果提供了可選的整數引數 *depth*,則該函式返回堆疊頂部以下 *depth* 次呼叫的幀。例如,sys._getframe(1)
返回呼叫者的幀物件。此函式僅存在於 CPython 中,而不存在於 Jython 或 .NET 實現中。使用它進行除錯,並抵制將其放入生產程式碼的誘惑。
其他更改和修復¶
由於釋出週期較短,Python 2.1 中的較小更改相對較少。搜尋 CVS 更改日誌會發現應用了 117 個補丁,並修復了 136 個錯誤;這兩個數字都可能被低估了。一些更值得注意的更改是
現在可以選擇使用一個專門的物件分配器,它應該比系統的
malloc()
快,並且記憶體開銷更小。分配器使用 C 的malloc()
函式來獲取大量的記憶體池,然後從這些池中滿足較小的記憶體請求。可以透過向 configure 指令碼提供--with-pymalloc
選項來啟用它;有關實現細節,請參閱Objects/obmalloc.c
。C 擴充套件模組的作者應該在啟用物件分配器的情況下測試他們的程式碼,因為一些不正確的程式碼可能會中斷,導致執行時核心轉儲。Python 的 C API 中有一堆記憶體分配函式,這些函式以前只是 C 庫的
malloc()
和free()
的別名,這意味著如果你意外地呼叫了不匹配的函式,則不會注意到錯誤。當啟用物件分配器時,這些函式不再是malloc()
和free()
的別名,並且呼叫錯誤的函式來釋放記憶體會導致核心轉儲。例如,如果記憶體是使用PyMem_New
分配的,則必須使用PyMem_Del()
而不是free()
來釋放它。Python 附帶的幾個模組也犯了這個錯誤,必須修復;毫無疑問,還有更多第三方模組也會遇到同樣的問題。物件分配器由 Vladimir Marangozov 貢獻。
面向行的檔案 I/O 的速度得到了提高,因為人們經常抱怨它的速度不夠快,並且因為它經常被用作幼稚的基準。因此,檔案物件的
readline()
方法已被重寫,速度更快。加速的具體程度因平臺而異,具體取決於 C 庫的getc()
的速度有多慢,但大約為 66%,並且在某些特定的作業系統上可能會更快。Tim Peters 為此更改做了大量的基準測試和編碼工作,這源於 comp.lang.python 中的一次討論。Jeff Epler 還貢獻了一個新的檔案物件模組和方法。新方法
xreadlines()
類似於現有的xrange()
內建函式。xreadlines()
返回一個不透明的序列物件,該物件僅支援迭代,每次迭代讀取一行,但不會像現有的readlines()
方法那樣將整個檔案讀取到記憶體中。你可以像這樣使用它for line in sys.stdin.xreadlines(): # ... do something for each line ... ...
有關行 I/O 更改的更詳細討論,請參閱 2001 年 1 月 1 日至 15 日的 python-dev 摘要,網址為 https://mail.python.org/pipermail/python-dev/2001-January/。
字典添加了一個新的方法
popitem()
,用於以破壞性方式遍歷字典的內容;對於大型字典,這可以更快,因為無需構建包含所有鍵或值的列表。D.popitem()
從字典D
中刪除一個隨機的(key, value)
對,並將其作為 2 元組返回。此方法主要由 Tim Peters 和 Guido van Rossum 實現,基於 Moshe Zadka 的建議和初步補丁。模組現在可以透過定義一個包含要匯入的名稱列表的
__all__
屬性,來控制使用from module import *
時匯入哪些名稱。一個常見的抱怨是,如果模組匯入了其他模組(例如sys
或string
),from module import *
會將它們新增到匯入模組的名稱空間中。要解決此問題,只需在__all__
中列出公共名稱即可。# List public names __all__ = ['Database', 'open']
Ben Wolfson 首先提出並實現了此補丁的更嚴格版本,但在經過一些 python-dev 的討論後,最終採用了一個較弱的版本。
以前對字串應用
repr()
時,非列印字元會使用八進位制轉義;例如,換行符為'\012'
。這是 Python C 語言起源的殘留痕跡,但今天八進位制幾乎沒有實際用途。Ka-Ping Yee 建議使用十六進位制轉義代替八進位制,並對適當的字元使用\n
,\t
,\r
轉義,並實現了這種新的格式。現在,在編譯時檢測到的語法錯誤可以引發包含錯誤檔名和行號的異常,這是 Jeremy Hylton 完成的編譯器重組帶來的一個令人愉快的副作用。
匯入其他模組的 C 擴充套件已更改為使用
PyImport_ImportModule()
,這意味著它們將使用任何已安裝的匯入鉤子。對於需要從 C 程式碼匯入其他模組的第三方擴充套件,也鼓勵這樣做。感謝 Fredrik Lundh,Unicode 字元資料庫的大小又縮小了 340K。
貢獻了一些新的移植:MacOS X (Steven Majewski 貢獻),Cygwin (Jason Tishler 貢獻);RISCOS (Dietmar Schwertberger 貢獻);Unixware 7 (Billy G. Allie 貢獻)。
還有通常的次要錯誤修復、次要記憶體洩漏、文件字串編輯和其他調整列表,由於太長而不值得一一列舉;如果需要,請參閱 CVS 日誌以獲取完整詳細資訊。
致謝¶
作者要感謝以下人員為本文的各種草稿提供建議:Graeme Cross、David Goodger、Jay Graves、Michael Hudson、Marc-André Lemburg、Fredrik Lundh、Neil Schemenauer、Thomas Wouters。