Python 2.1 中的新功能

作者:

A.M. Kuchling

引言

本文解釋了 Python 2.1 中的新功能。儘管 2.1 中的變化不如 Python 2.0 多,但仍然有一些令人驚喜之處。2.1 是第一個透過 Python 增強提案(即 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 預設引數現在是不必要的。簡單來說,當一個給定的變數名在一個函式中沒有被賦值(透過賦值,或者 defclassimport 語句),對該變數的引用將在其 enclosing 作用域的區域性名稱空間中查詢。關於規則的更詳細解釋以及實現的剖析,可以在 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 的使用者常常覺得這種模型過於弱和限制性,因為在 Numeric Python 用於的數字處理程式中,能夠對兩個矩陣進行逐元素比較,返回一個包含每個元素的給定比較結果的矩陣會更有用。如果兩個矩陣的大小不同,那麼比較必須能夠引發異常來表示錯誤。

在 Python 2.1 中,添加了豐富的比較以支援此需求。Python 類現在可以單獨過載 <<=>>===!= 操作。新的魔術方法名稱是

操作

方法名稱

<

__lt__()

<=

__le__()

>

__gt__()

>=

__ge__()

==

__eq__()

!=

__ne__()

(這些魔術方法以相應的 Fortran 運算子 .LT..LE. 等命名。數值程式設計師幾乎肯定對這些名稱非常熟悉,並且會覺得它們容易記住。)

這些魔術方法中的每一個都採用 method(self, other) 的形式,其中 self 將是運算子左側的物件,而 other 將是右側的物件。例如,表示式 A < B 將導致呼叫 A.__lt__(B)

這些魔術方法中的每一個都可以返回任何值:布林值、矩陣、列表或任何其他 Python 物件。或者,如果比較不可能、不一致或沒有意義,它們也可以引發異常。

內建的 cmp(A,B) 函式可以使用豐富的比較機制,現在接受一個可選引數來指定要使用的比較操作;該引數是字串 "<""<="">"">=""==""!=" 之一。如果呼叫時沒有可選的第三個引數,cmp() 將像以前的 Python 版本一樣只返回 -1、0 或 +1;否則它將呼叫適當的方法並可以返回任何 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: 警告框架

在 Python 存在的 10 年裡,它積累了一定數量的過時模組和功能。很難知道何時可以安全地刪除某個功能,因為無法知道有多少程式碼使用它——也許沒有程式依賴該功能,也許有很多。為了以更結構化的方式刪除舊功能,添加了一個警告框架。當 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 5 - 語言演進指南

由 Paul Prescod 撰寫,旨在規定從 Python 中刪除舊功能時應遵循的程式。本 PEP 中描述的政策尚未正式採用,但最終政策可能與 Prescod 的提案不會有太大差異。

PEP 230 - 警告框架

由 Guido van Rossum 撰寫並實現。

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 更快,也使得修改 Makefiles 更清晰、更簡單。

參見

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.PYfile.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 月停用,可在 Internet Archive Wayback Machine 中找到)是 Python 模組最大的目錄,但在 Vaults 註冊軟體是可選的,許多人都不屑一顧。

作為解決此問題的第一步,使用 Distutils sdist 命令打包的 Python 軟體將包含一個名為 PKG-INFO 的檔案,其中包含有關包的資訊,例如其名稱、版本和作者(在編目術語中稱為元資料)。PEP 241 包含了 PKG-INFO 檔案中可以存在的所有欄位。隨著人們開始使用 Python 2.1 打包他們的軟體,越來越多的包將包含元資料,從而可以構建自動化編目系統並對其進行實驗。透過積累經驗,或許可以設計一個真正好的目錄,然後將其支援內建到 Python 2.2 中。例如,Distutils 的 sdistbdist_* 命令可以支援 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/

參見

PEP 241 - Python 軟體包元資料

由 A.M. Kuchling 撰寫並實現。

PEP 243 - 模組倉庫上傳機制

由 Sean Reifschneider 撰寫,這份草案 PEP 描述了將 Python 包上傳到中央伺服器的提議機制。

新增和改進的模組

  • 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 很快就會讓人上癮;快試試吧!

  • 標準庫中添加了兩個用於單元測試的不同模組。doctest 模組由 Tim Peters 貢獻,提供了一個基於執行文件字串中嵌入示例並將結果與預期輸出進行比較的測試框架。PyUnit 由 Steve Purcell 貢獻,是一個受 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 的一部分)的一個包裝器。面板庫提供了具有額外深度功能的視窗。視窗可以在深度排序中向上或向下移動,面板庫會計算面板重疊的位置以及哪些部分是可見的。

  • PyXML 包自 Python 2.0 以來已經發布了幾個版本,Python 2.1 包含了更新版本的 xml 包。一些值得注意的更改包括支援 Expat 1.2 及更高版本、Expat 解析器處理 Python 支援的任何編碼的檔案能力,以及 SAX、DOM 和 minidom 模組的各種錯誤修復。

  • Ping 還貢獻了另一個用於處理未捕獲異常的鉤子。sys.excepthook() 可以設定為一個可呼叫物件。當異常未被任何 tryexcept 塊捕獲時,異常將傳遞給 sys.excepthook(),然後它可以做任何它想做的事情。在第九屆 Python 大會上,Ping 展示了這個鉤子的一種應用:列印一個擴充套件的追溯,它不僅列出了堆疊幀,還列出了每個幀的函式引數和區域性變數。

  • 模組 time 中的各種函式,例如 asctime()localtime(),需要一個浮點引數,其中包含自紀元以來的秒數。這些函式最常見的用途是處理當前時間,因此浮點引數已變為可選;當未提供值時,將使用當前時間。例如,日誌檔案條目通常需要一個包含當前時間的字串;在 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 提出了建議和初步補丁。

  • 當使用 from module import * 時,模組現在可以控制哪些名稱被匯入,方法是定義一個包含要匯入名稱列表的 __all__ 屬性。一個常見的抱怨是,如果模組匯入其他模組(例如 sysstring),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。