Python 3.0 的新功能

作者:

Guido van Rossum

本文介紹了 Python 3.0 相較於 2.6 的新功能。Python 3.0,也稱為 “Python 3000” 或 “Py3K”,是有史以來第一個 故意向後不相容 的 Python 版本。Python 3.0 於 2008 年 12 月 3 日釋出。與典型版本相比,此次更改更多,其中許多對所有 Python 使用者都很重要。然而,消化這些更改後,你會發現 Python 實際上並沒有改變太多——總的來說,我們主要是修復了一些眾所周知的不便和缺陷,並刪除了許多舊的冗餘內容。

本文不旨在提供所有新功能的完整規範,而是嘗試提供一個方便的概述。有關完整詳情,請參閱 Python 3.0 的文件和/或文字中引用的許多 PEP。如果你想了解某個特定功能的完整實現和設計原理,PEP 通常比常規文件包含更多詳細資訊;但請注意,一旦某個功能完全實現,PEP 通常不會保持更新。

由於時間限制,本文件並不像它應有的那樣完整。與新版本釋出時一樣,原始碼分發中的 Misc/NEWS 檔案包含有關每個微小更改的大量詳細資訊。

常見障礙

本節列出了少數幾個如果你習慣使用 Python 2.5 最容易遇到的更改。

檢視和迭代器取代列表

一些知名的 API 不再返回列表

  • dict 方法 dict.keys()dict.items()dict.values() 返回“檢視”而不是列表。例如,k = d.keys(); k.sort() 不再起作用。請改用 k = sorted(d)(此方法在 Python 2.5 中也有效,且效率相同)。

  • 此外,dict.iterkeys()dict.iteritems()dict.itervalues() 方法不再受支援。

  • map()filter() 返回迭代器。如果你確實需要一個列表且輸入序列長度都相等,一個快速解決方案是將 map() 封裝在 list() 中,例如 list(map(...)),但更好的解決方案通常是使用列表推導式(尤其是當原始程式碼使用 lambda 時),或者重寫程式碼使其根本不需要列表。特別棘手的是因函式副作用而呼叫的 map();正確的轉換是使用常規的 for 迴圈(因為建立列表只會浪費資源)。

    如果輸入序列長度不相等,map() 將在最短序列終止時停止。為了與 Python 2.x 的 map() 完全相容,還需要將序列封裝在 itertools.zip_longest() 中,例如 map(func, *sequences) 變為 list(map(func, itertools.zip_longest(*sequences)))

  • range() 現在行為與過去的 xrange() 相同,只是它適用於任意大小的值。後者不再存在。

  • zip() 現在返回一個迭代器。

排序比較

Python 3.0 簡化了排序比較的規則

  • 當運算元沒有有意義的自然順序時,排序比較運算子(<<=>=>)會引發 TypeError 異常。因此,像 1 < ''0 > Nonelen <= len 這樣的表示式不再有效,例如 None < None 會引發 TypeError 而不是返回 False。因此,對異構列表進行排序不再有意義——所有元素都必須相互可比較。請注意,這不適用於 ==!= 運算子:不同不可比較型別的物件總是相互比較不相等。

  • sorted()list.sort() 不再接受提供比較函式的 cmp 引數。請改用 key 引數。注意,keyreverse 引數現在是“僅限關鍵字”的。

  • cmp() 函式應被視為已刪除,__cmp__() 特殊方法不再受支援。請使用 __lt__() 進行排序,__eq__()__hash__() 配合使用,以及根據需要使用其他富比較。(如果你確實需要 cmp() 功能,可以使用表示式 (a > b) - (a < b) 作為 cmp(a, b) 的等效項。)

整數

  • PEP 237:本質上,long 重新命名為 int。也就是說,只有一個名為 int 的內建整型,但它的行為大部分類似於舊的 long 型別。

  • PEP 238:像 1/2 這樣的表示式返回浮點數。使用 1//2 獲取截斷行為。(後者的語法已經存在多年,至少自 Python 2.2 以來。)

  • sys.maxint 常量已被移除,因為整數的值不再有上限。但是,sys.maxsize 可以用作大於任何實際列表或字串索引的整數。它符合實現的“自然”整數大小,並且通常與先前版本在同一平臺上的 sys.maxint 相同(假設相同的構建選項)。

  • 長整數的 repr() 不再包含末尾的 L,因此無條件刪除該字元的程式碼將改為截斷最後一位數字。(請改用 str()。)

  • 八進位制字面量不再是 0720 的形式;請改用 0o720

文字與資料取代 Unicode 與 8 位字串

你以前所瞭解的關於二進位制資料和 Unicode 的一切都變了。

  • Python 3.0 使用 文字 和(二進位制) 資料 的概念,而不是 Unicode 字串和 8 位字串。所有文字都是 Unicode;然而 編碼後 的 Unicode 表示為二進位制資料。用於儲存文字的型別是 str,用於儲存資料的型別是 bytes。與 2.x 的情況最大的區別在於,Python 3.0 中任何嘗試混合文字和資料的操作都會引發 TypeError,而在 Python 2.x 中,如果你混合 Unicode 和 8 位字串,如果 8 位字串恰好只包含 7 位(ASCII)位元組,它就會工作,但如果它包含非 ASCII 值,你就會得到 UnicodeDecodeError。這種特定於值的行為多年來導致了無數的沮喪。

  • 由於這一哲學上的改變,幾乎所有使用 Unicode、編碼或二進位制資料的程式碼都可能需要修改。這種改變是更好的,因為在 2.x 世界中,存在大量與混合編碼和未編碼文字有關的 bug。為了在 Python 2.x 中做好準備,開始對所有未編碼文字使用 unicode,並且只對二進位制或編碼資料使用 str。然後 2to3 工具將為你完成大部分工作。

  • 你不再可以使用 u"..." 字面量表示 Unicode 文字。但是,你必須使用 b"..." 字面量表示二進位制資料。

  • 由於 strbytes 型別不能混合使用,你必須始終在它們之間顯式轉換。使用 str.encode()str 轉換為 bytes,使用 bytes.decode()bytes 轉換為 str。你也可以分別使用 bytes(s, encoding=...)str(b, encoding=...)

  • str 一樣,bytes 型別也是不可變的。有一個單獨的 可變 型別用於儲存緩衝的二進位制資料,即 bytearray。幾乎所有接受 bytes 的 API 也接受 bytearray。可變 API 基於 collections.MutableSequence

  • 原始字串字面量中的所有反斜槓都按字面解釋。這意味著原始字串中的 '\U''\u' 轉義序列不會被特殊處理。例如,r'\u20ac' 在 Python 3.0 中是一個包含 6 個字元的字串,而在 2.6 中,ur'\u20ac' 是單個“歐元”字元。(當然,此更改僅影響原始字串字面量;在 Python 3.0 中,歐元字元是 '\u20ac'。)

  • 內建的抽象型別 basestring 已被移除。請改用 strstrbytes 型別的功能沒有足夠的共同點來保證共享基類。2to3 工具(見下文)將所有出現的 basestring 替換為 str

  • 以文字檔案模式開啟的檔案(open() 仍預設為此模式)始終使用編碼在字串(記憶體中)和位元組(磁碟上)之間進行對映。二進位制檔案(以模式引數中的 b 開啟)始終在記憶體中使用位元組。這意味著如果檔案以不正確的模式或編碼開啟,I/O 很可能會大聲失敗,而不是靜默地產生不正確的資料。這也意味著即使是 Unix 使用者在開啟檔案時也必須指定正確的模式(文字或二進位制)。存在一個平臺相關的預設編碼,在 Unix 平臺下可以透過 LANG 環境變數(有時也透過其他平臺特定的區域設定相關環境變數)進行設定。在許多情況下,但並非所有情況下,系統預設編碼是 UTF-8;你不應該依賴此預設值。任何讀寫純 ASCII 文字之外的應用程式都應該有辦法覆蓋編碼。不再需要使用 codecs 模組中支援編碼的流。

  • sys.stdinsys.stdoutsys.stderr 的初始值現在是僅限 Unicode 的文字檔案(即,它們是 io.TextIOBase 的例項)。要使用這些流讀寫位元組資料,你需要使用它們的 io.TextIOBase.buffer 屬性。

  • 檔名作為(Unicode)字串傳遞給 API 並從 API 返回。這可能會帶來平臺特定問題,因為在某些平臺上,檔名是任意位元組字串。(另一方面,在 Windows 上,檔名原生儲存為 Unicode。)作為一種變通方法,大多數接受檔名的 API(例如 open()os 模組中的許多函式)都接受 bytes 物件和字串,並且少數 API 具有請求 bytes 返回值的方法。因此,如果引數是 bytes 例項,os.listdir() 返回一個 bytes 例項列表,而 os.getcwdb() 返回當前工作目錄作為 bytes 例項。請注意,當 os.listdir() 返回字串列表時,無法正確解碼的檔名將被省略,而不是引發 UnicodeError

  • 某些系統 API,例如 os.environsys.argv,當系統提供的位元組無法使用預設編碼解釋時,也可能出現問題。設定 LANG 變數並重新執行程式可能是最好的方法。

  • PEP 3138:字串的 repr() 不再轉義非 ASCII 字元。但它仍然轉義 Unicode 標準中具有不可列印狀態的控制字元和碼點。

  • PEP 3120:預設原始碼編碼現在是 UTF-8。

  • PEP 3131:識別符號中現在允許使用非 ASCII 字母。(但是,標準庫仍然只包含 ASCII 字元,註釋中的貢獻者姓名除外。)

  • StringIOcStringIO 模組已刪除。相反,請匯入 io 模組,並分別使用 io.StringIOio.BytesIO 處理文字和資料。

  • 另請參閱針對 Python 3.0 更新的 Unicode HOWTO

語法變更概述

本節簡要概述了 Python 3.0 中所有 語法 更改。

新語法

  • PEP 3107:函式引數和返回值註解。這提供了一種標準化方式來註解函式的引數和返回值。除了可以透過 __annotations__ 屬性在執行時進行自省之外,此類註解沒有附加語義。其目的是透過元類、裝飾器或框架鼓勵實驗。

  • PEP 3102:僅限關鍵字引數。在引數列表中 *args 之後出現的命名引數 必須 在呼叫時使用關鍵字語法指定。你也可以在引數列表中使用裸 * 來表示你不接受可變長度引數列表,但你確實有僅限關鍵字引數。

  • 類定義中基類列表之後允許使用關鍵字引數。這被用於指定元類的新約定(參見下一節),但也可以用於其他目的,只要元類支援它。

  • PEP 3104nonlocal 語句。使用 nonlocal x,你現在可以直接賦值給外部(但非全域性)作用域中的變數。nonlocal 是一個新的保留字。

  • PEP 3132:擴充套件可迭代解包。你現在可以編寫類似 a, b, *rest = some_sequence 的程式碼。甚至可以寫 *rest, a = stuffrest 物件始終是(可能為空的)列表;右側可以是任何可迭代物件。示例:

    (a, *rest, b) = range(5)
    

    這將 a 設定為 0b 設定為 4rest 設定為 [1, 2, 3]

  • 字典推導式:{k: v for k, v in stuff} 的含義與 dict(stuff) 相同,但更靈活。(這是 PEP 274 的證明。:-)

  • 集合字面量,例如 {1, 2}。請注意,{} 是一個空字典;使用 set() 表示一個空集合。集合推導式也受支援;例如,{x for x in stuff} 的含義與 set(stuff) 相同,但更靈活。

  • 新的八進位制字面量,例如 0o720(已在 2.6 中)。舊的八進位制字面量(0720)已移除。

  • 新的二進位制字面量,例如 0b1010(已在 2.6 中),並且有一個新的相應內建函式 bin()

  • 位元組字面量以 bB 開頭,並且有一個新的相應內建函式 bytes()

改變的語法

  • PEP 3109PEP 3134:新的 raise 語句語法:raise [expr [from expr]]。見下文。

  • aswith 現在是保留字。(實際上自 2.6 以來就是。)

  • True, False, 和 None 是保留字。(2.6 已經部分強制執行了對 None 的限制。)

  • except exc, var 更改為 except exc as var。參見 PEP 3110

  • PEP 3115:新元類語法。不再使用

    class C:
        __metaclass__ = M
        ...
    

    你現在必須使用

    class C(metaclass=M):
        ...
    

    模組全域性變數 __metaclass__ 不再受支援。(它是一個柺杖,用於更容易地預設使用新式類,而無需從 object 派生每個類。)

  • 列表推導式不再支援語法形式 [... for var in item1, item2, ...]。請改用 [... for var in (item1, item2, ...)]。另請注意,列表推導式具有不同的語義:它們更接近於 list() 建構函式內部生成器表示式的語法糖,特別是迴圈控制變數不再洩漏到周圍作用域。

  • 省略號 (...) 可以作為原子表示式在任何地方使用。(以前只允許在切片中使用。)此外,它現在 必須 拼寫為 ...。(以前也可以拼寫為 . . .,這只是語法的一個意外。)

移除的語法

  • PEP 3113:元組引數解包已移除。你不能再寫 def foo(a, (b, c)): ...。請改用 def foo(a, b_c): b, c = b_c

  • 移除了反引號(請改用 repr())。

  • 移除了 <>(請改用 !=)。

  • 移除了關鍵字:exec() 不再是關鍵字;它仍然是一個函式。(幸運的是,函式語法在 2.x 中也接受。)另請注意,exec() 不再接受流引數;你可以使用 exec(f.read()) 而不是 exec(f)

  • 整數字面量不再支援末尾的 lL

  • 字串字面量不再支援前導的 uU

  • module import * 語法只允許在模組級別使用,不再允許在函式內部使用。

  • 相對匯入唯一可接受的語法是 from .[module] import name。所有不以 . 開頭的 import 形式都被解釋為絕對匯入。(PEP 328

  • 經典類已移除。

Python 2.6 中已存在的更改

由於許多使用者可能直接從 Python 2.5 跳到 Python 3.0,本節提醒讀者注意最初為 Python 3.0 設計但已反向移植到 Python 2.6 的新功能。有關更長的描述,應查閱 Python 2.6 的新功能 中的相應章節。

庫更改

由於時間限制,本文件未能詳盡涵蓋標準庫中非常廣泛的更改。PEP 3108 是庫主要更改的參考。以下是簡要回顧:

  • 許多舊模組被移除。有些,如 gopherlib(不再使用)和 md5(被 hashlib 取代),已經由 PEP 4 棄用。其他的移除是由於移除了對各種平臺(如 Irix、BeOS 和 Mac OS 9)的支援(參見 PEP 11)。一些模組也因缺乏使用或存在更好的替代品而被選定在 Python 3.0 中移除。有關詳盡列表,請參見 PEP 3108

  • bsddb3 包已被移除,因為事實證明它在核心標準庫中的存在給核心開發人員帶來了特別大的負擔,原因在於測試不穩定和 Berkeley DB 的釋出計劃。然而,該包仍然活躍,並在外部維護於 https://www.jcea.es/programacion/pybsddb.htm

  • 有些模組因其舊名稱不符合 PEP 8 或其他各種原因而被重新命名。以下是列表:

    舊名稱

    新名稱

    _winreg

    winreg

    ConfigParser

    configparser

    copy_reg

    copyreg

    佇列

    queue

    SocketServer

    socketserver

    markupbase

    _markupbase

    repr

    reprlib

    test.test_support

    test.support

  • Python 2.x 中常見的模式是有一個純 Python 實現的模組版本,以及一個可選的 C 擴充套件實現的加速版本;例如,picklecPickle。這使得每個使用這些模組的使用者都必須承擔匯入加速版本並回退到純 Python 版本的負擔。在 Python 3.0 中,加速版本被視為純 Python 版本的實現細節。使用者應該始終匯入標準版本,它會嘗試匯入加速版本並回退到純 Python 版本。pickle / cPickle 對受到了這種處理。profile 模組在 3.1 的列表中。StringIO 模組已在 io 模組中變為一個類。

  • 一些相關模組已被分組到包中,並且通常子模組名稱已簡化。由此產生的新包是:

    • dbmanydbmdbhashdbmdumbdbmgdbmwhichdb)。

    • htmlHTMLParserhtmlentitydefs)。

    • httphttplibBaseHTTPServerCGIHTTPServerSimpleHTTPServerCookiecookielib)。

    • tkinter(除了 turtle 之外的所有 Tkinter 相關模組)。turtle 的目標受眾並不關心 tkinter。另請注意,自 Python 2.6 起,turtle 的功能已大大增強。

    • urlliburlliburllib2urlparserobotparse)。

    • xmlrpcxmlrpclibDocXMLRPCServerSimpleXMLRPCServer)。

標準庫模組的其他一些更改,PEP 3108 未涵蓋:

  • 移除了 sets。請使用內建的 set() 類。

  • sys 模組的清理:移除了 sys.exitfunc()sys.exc_clear()sys.exc_typesys.exc_valuesys.exc_traceback。(注意 sys.last_type 等仍然保留。)

  • array.array 型別的清理:read()write() 方法已移除;請改用 fromfile()tofile()。此外,陣列的 'c' 型別碼已移除——請使用 'b' 表示位元組或 'u' 表示 Unicode 字元。

  • operator 模組的清理:移除了 sequenceIncludes()isCallable()

  • thread 模組的清理:acquire_lock()release_lock() 已移除;請改用 acquire()release()

  • random 模組的清理:移除了 jumpahead() API。

  • new 模組已移除。

  • os.tmpnam()os.tempnam()os.tmpfile() 函式已移除,取而代之的是 tempfile 模組。

  • tokenize 模組已更改為使用位元組。主要入口點現在是 tokenize.tokenize(),而不是 generate_tokens。

  • string.letters 及其朋友(string.lowercasestring.uppercase)已移除。請改用 string.ascii_letters 等。(移除的原因是 string.letters 及其朋友具有區域設定特定的行為,這對於如此吸引人的全域性“常量”來說是個壞主意。)

  • 模組 __builtin__ 已重新命名為 builtins(去掉了下劃線,添加了 's')。大多數全域性名稱空間中的 __builtins__ 變數未更改。要修改內建函式,你應該使用 builtins,而不是 __builtins__

PEP 3101:字串格式化的新方法

  • 一個新的內建字串格式化作業系統取代了 % 字串格式化運算子。(然而,% 運算子仍受支援;它將在 Python 3.1 中棄用,並在稍後從語言中移除。)請閱讀 PEP 3101 瞭解所有詳細資訊。

異常更改

引發和捕獲異常的 API 已清理,並添加了強大的新功能。

  • PEP 352:所有異常都必須(直接或間接)派生自 BaseException。這是異常層次結構的根。作為建議,這不是新內容,但繼承自 BaseException要求 是新內容。(Python 2.6 仍然允許引發經典類,並且對你可以捕獲的內容沒有限制。)因此,字串異常終於真正徹底地消失了。

  • 幾乎所有異常實際上都應該派生自 ExceptionBaseException 應該只用作僅在頂層處理的異常的基類,例如 SystemExitKeyboardInterrupt。處理除後者以外所有異常的推薦慣例是使用 except Exception

  • StandardError 已移除。

  • 異常不再作為序列行為。請改用 args 屬性。

  • PEP 3109:引發異常。你現在必須使用 raise Exception(args) 而不是 raise Exception, args。此外,你不能再顯式指定回溯;相反,如果你 必須 這樣做,你可以直接賦值給 __traceback__ 屬性(見下文)。

  • PEP 3110:捕獲異常。你現在必須使用 except SomeException as variable 而不是 except SomeException, variable。此外,當 except 塊結束時,variable 會被顯式刪除。

  • PEP 3134:異常鏈。有兩種情況:隱式鏈和顯式鏈。隱式鏈發生在 exceptfinally 處理程式塊中引發異常時。這通常是由於處理程式塊中的錯誤造成的;我們稱之為 次要 異常。在這種情況下,原始異常(正在處理的異常)將作為次要異常的 __context__ 屬性儲存。顯式鏈使用此語法呼叫:

    raise SecondaryException() from primary_exception
    

    (其中 primary_exception 是任何產生異常物件的表示式,可能是之前捕獲的異常)。在這種情況下,主異常儲存在次要異常的 __cause__ 屬性上。當發生未處理的異常時列印的回溯會遍歷 __cause____context__ 屬性鏈,併為鏈的每個元件列印單獨的回溯,主異常位於頂部。(Java 使用者可能會識別此行為。)

  • PEP 3134:異常物件現在將其回溯儲存為 __traceback__ 屬性。這意味著異常物件現在包含與異常相關的所有資訊,使用 sys.exc_info() 的原因更少(儘管後者並未移除)。

  • 當 Windows 無法載入擴充套件模組時,一些異常訊息得到了改進。例如,error code 193 現在是 %1 is not a valid Win32 application。字串現在處理非英語語言環境。

其他雜項更改

運算子和特殊方法

  • != 現在返回 == 的相反值,除非 == 返回 NotImplemented

  • 語言中已刪除“未繫結方法”的概念。現在,當將方法作為類屬性引用時,你會得到一個純函式物件。

  • __getslice__()__setslice__()__delslice__() 已被移除。語法 a[i:j] 現在轉換為 a.__getitem__(slice(i, j))(或 __setitem__()__delitem__(),分別用於賦值或刪除目標時)。

  • PEP 3114:標準的 next() 方法已更名為 __next__()

  • 特殊方法 __oct__()__hex__() 已移除 – oct()hex() 現在使用 __index__() 將引數轉換為整數。

  • 移除了對 __members____methods__ 的支援。

  • 命名為 func_X 的函式屬性已重新命名為使用 __X__ 形式,從而將這些名稱從函式屬性名稱空間中釋放出來供使用者定義屬性使用。也就是說,func_closurefunc_codefunc_defaultsfunc_dictfunc_docfunc_globalsfunc_name 分別重新命名為 __closure____code____defaults____dict____doc____globals____name__

  • __nonzero__() 現在是 __bool__()

內建函式

  • PEP 3135:新的 super()。現在,您可以在不帶引數的情況下呼叫 super(),並且(假設它是在 class 語句中定義的常規例項方法中)將自動選擇正確的類和例項。帶引數時,super() 的行為保持不變。

  • PEP 3111raw_input() 已重新命名為 input()。也就是說,新的 input() 函式從 sys.stdin 讀取一行並返回,並去除末尾的換行符。如果輸入過早終止,它會引發 EOFError。要獲得 input() 的舊行為,請使用 eval(input())

  • 添加了一個新的內建函式 next(),用於呼叫物件上的 __next__() 方法。

  • round() 函式的舍入策略和返回型別已更改。精確的中間情況現在舍入到最接近的偶數結果,而不是遠離零。(例如,round(2.5) 現在返回 2 而不是 3。)round(x[, n]) 現在委託給 x.__round__([n]),而不是總是返回浮點數。當用單個引數呼叫時,它通常返回一個整數;當用兩個引數呼叫時,它返回與 x 型別相同的值。

  • intern() 移至 sys.intern()

  • 已移除:apply()。現在,使用 f(*args) 而不是 apply(f, args)

  • 已移除 callable()。現在,使用 isinstance(f, collections.Callable) 而不是 callable(f)。函式 operator.isCallable() 也已移除。

  • 已移除 coerce()。由於經典類已不復存在,此函式不再有用。

  • 已移除 execfile()。現在,使用 exec(open(fn).read()) 而不是 execfile(fn)

  • 已移除 file 型別。請使用 open()。現在,io 模組中 open 可以返回幾種不同型別的流。

  • 已移除 reduce()。如果您確實需要它,請使用 functools.reduce();然而,99% 的情況下,顯式的 for 迴圈更具可讀性。

  • 已移除 reload()。請使用 imp.reload()

  • 已移除。dict.has_key() – 請改用 in 運算子。

構建和 C API 更改

由於時間限制,這裡列出了 C API 更改的 *非常* 不完整的列表。

  • 已停止支援多個平臺,包括但不限於 Mac OS 9、BeOS、RISCOS、Irix 和 Tru64。

  • PEP 3118:新緩衝區 API。

  • PEP 3121:擴充套件模組初始化與終結。

  • PEP 3123:使 PyObject_HEAD 符合標準 C。

  • 不再支援 C API 的受限執行。

  • PyNumber_Coerce()PyNumber_CoerceEx()PyMember_Get()PyMember_Set() C API 已移除。

  • 新的 C API PyImport_ImportModuleNoBlock(),其功能類似於 PyImport_ImportModule(),但不會在匯入鎖上阻塞(而是返回錯誤)。

  • 布林轉換 C 級槽和方法已重新命名:nb_nonzero 現在是 nb_bool

  • 從 C API 中移除了 METH_OLDARGSWITH_CYCLE_GC

效能

Python 3.0 泛化的最終結果是,Python 3.0 執行 pystone 基準測試比 Python 2.5 慢約 10%。最大的原因很可能是取消了對小整數的特殊處理。仍有改進的空間,但這將在 3.0 釋出後進行!

移植到 Python 3.0

要將現有 Python 2.5 或 2.6 原始碼移植到 Python 3.0,最佳策略如下:

  1. (先決條件:) 從出色的測試覆蓋率開始。

  2. 移植到 Python 2.6。這應該不比從 Python 2.x 移植到 Python 2.(x+1) 的平均工作量大。確保所有測試都透過。

  3. (仍使用 2.6:) 啟用 -3 命令列開關。這將啟用有關 3.0 中將移除(或更改)的功能的警告。再次執行您的測試套件,並修復您收到警告的程式碼,直到沒有警告,並且所有測試仍然透過。

  4. 在您的原始碼樹上執行 2to3 原始碼到原始碼轉換器。在 Python 3.0 下執行轉換結果。手動修復任何剩餘問題,直到所有測試再次透過。

不建議嘗試編寫在 Python 2.6 和 3.0 下均不變執行的原始碼;您將不得不使用非常扭曲的編碼風格,例如避免 print 語句、元類等等。如果您正在維護一個需要同時支援 Python 2.6 和 Python 3.0 的庫,最好的方法是透過編輯 2.6 版本的原始碼並再次執行 2to3 轉換器來修改上述第 3 步,而不是編輯 3.0 版本的原始碼。

有關將 C 擴充套件移植到 Python 3.0 的資訊,請參閱 將擴充套件模組移植到 Python 3