2to3 — 自動化 Python 2 到 3 程式碼轉換¶
2to3 是一個 Python 程式,它讀取 Python 2.x 原始碼並應用一系列修復程式將其轉換為有效的 Python 3.x 程式碼。標準庫包含一組豐富的修復程式,幾乎可以處理所有程式碼。2to3 支援庫 lib2to3
然而,是一個靈活且通用的庫,因此可以為 2to3 編寫自己的修復程式。
自 3.11 版棄用,將在 3.13 版中移除: lib2to3
模組在 Python 3.9 中標記為待棄用(匯入時引發 PendingDeprecationWarning
)並在 Python 3.11 中完全棄用(引發 DeprecationWarning
)。2to3
工具是其中的一部分。它將在 Python 3.13 中移除。
使用 2to3¶
2to3 通常會作為指令碼與 Python 直譯器一起安裝。它還位於 Python 根目錄的 Tools/scripts
目錄中。
2to3 的基本引數是要轉換的檔案或目錄列表。目錄將遞迴遍歷以查詢 Python 原始碼。
以下是一個示例 Python 2.x 原始檔 example.py
def greet(name):
print "Hello, {0}!".format(name)
print "What's your name?"
name = raw_input()
greet(name)
可以透過命令列上的 2to3 將其轉換為 Python 3.x 程式碼
$ 2to3 example.py
將列印與原始原始檔相比的差異。2to3 還可以將所需的修改直接寫入原始檔。(除非還給出了 -n
,否則將備份原始檔案。)使用 -w
標誌啟用將更改寫回
$ 2to3 -w example.py
轉換後,example.py
如下所示
def greet(name):
print("Hello, {0}!".format(name))
print("What's your name?")
name = input()
greet(name)
在整個轉換過程中保留註釋和確切縮排。
預設情況下,2to3 執行一組 預定義修復程式。 -l
標誌列出所有可用的修復程式。可以使用 -f
給出要執行的明確修復程式集。同樣, -x
明確停用修復程式。以下示例僅執行 imports
和 has_key
修復程式
$ 2to3 -f imports -f has_key example.py
此命令執行除 apply
修復程式之外的每個修復程式
$ 2to3 -x apply example.py
某些修復程式是顯式的,這意味著它們不會預設執行,並且必須在命令列中列出才能執行。此處,除了預設修復程式之外,還執行 idioms
修復程式
$ 2to3 -f all -f idioms example.py
請注意如何傳遞 all
啟用所有預設修復程式。
有時,2to3 會在原始碼中找到需要更改的位置,但 2to3 無法自動修復。在這種情況下,2to3 會在檔案的 diff 下方列印警告。你應該解決警告以獲得相容的 3.x 程式碼。
2to3 還可以重構 doctest。要啟用此模式,請使用 -d
標誌。請注意,僅重構 doctest。這也並不需要模組是有效的 Python。例如,reST 文件中的類似 doctest 的示例也可以使用此選項進行重構。
-v
選項啟用輸出有關翻譯過程的更多資訊。
由於某些 print 語句可以解析為函式呼叫或語句,因此 2to3 並不總是可以讀取包含 print 函式的檔案。當 2to3 檢測到 from __future__ import print_function
編譯器指令的存在時,它會修改其內部語法以將 print()
解釋為函式。此更改也可以使用 -p
標誌手動啟用。使用 -p
對其 print 語句已轉換的程式碼執行修復程式。此外, -e
可用於使 exec()
成為函式。
-o
或 --output-dir
選項允許指定要將處理後的輸出檔案寫入的備用目錄。在不覆蓋輸入檔案時,使用此選項時需要 -n
標誌,因為備份檔案沒有意義。
在 3.2.3 版中新增: 添加了 -o
選項。
標誌 -W
或 --write-unchanged-files
告知 2to3 始終寫入輸出檔案,即使檔案不需要任何更改。這與 -o
結合使用時最有用,這樣便可將整個 Python 原始碼樹從一個目錄複製到另一個目錄,同時進行轉換。此選項隱含標誌 -w
,否則它沒有任何意義。
在版本 3.2.3 中新增: 添加了標誌 -W
。
選項 --add-suffix
指定要追加到所有輸出檔名的字串。指定此選項時需要標誌 -n
,因為寫入不同檔名時不需要備份。示例
$ 2to3 -n -W --add-suffix=3 example.py
將導致寫入一個名為 example.py3
的已轉換檔案。
在版本 3.2.3 中新增: 添加了選項 --add-suffix
。
要將整個專案從一個目錄樹轉換到另一個目錄樹,請使用
$ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode
修復程式¶
轉換程式碼的每個步驟都封裝在一個修復程式中。命令 2to3 -l
會列出它們。如 上述文件 所述,每個修復程式都可以單獨開啟和關閉。此處將詳細描述它們。
- apply¶
刪除
apply()
的用法。例如,apply(function, *args, **kwargs)
轉換為function(*args, **kwargs)
。
- asserts¶
用正確的名稱替換已棄用的
unittest
方法名稱。從
到
failUnlessEqual(a, b)
assertEquals(a, b)
failIfEqual(a, b)
assertNotEquals(a, b)
failUnless(a)
assert_(a)
failIf(a)
failUnlessRaises(exc, cal)
failUnlessAlmostEqual(a, b)
assertAlmostEquals(a, b)
failIfAlmostEqual(a, b)
assertNotAlmostEquals(a, b)
- buffer¶
將
buffer
轉換為memoryview
。此修復程式是可選的,因為memoryview
API 與buffer
的 API 類似,但並不完全相同。
- dict¶
修復字典迭代方法。將
dict.iteritems()
轉換為dict.items()
,將dict.iterkeys()
轉換為dict.keys()
,將dict.itervalues()
轉換為dict.values()
。類似地,將dict.viewitems()
、dict.viewkeys()
和dict.viewvalues()
分別轉換為dict.items()
、dict.keys()
和dict.values()
。它還將dict.items()
、dict.keys()
和dict.values()
的現有用法包裝在對list
的呼叫中。
- except¶
將
except X, T
轉換為except X as T
。
- funcattrs¶
修復已重新命名的函式屬性。例如,
my_function.func_closure
轉換為my_function.__closure__
。
- future¶
刪除
from __future__ import new_feature
語句。
- getcwdu¶
將
os.getcwdu()
重新命名為os.getcwd()
。
- has_key¶
將
dict.has_key(key)
更改為key in dict
。
- idioms¶
此可選修復程式執行多項轉換,使 Python 程式碼更符合慣用語。將
type(x) is SomeClass
和type(x) == SomeClass
等型別比較轉換為isinstance(x, SomeClass)
。while 1
變成while True
。此修復程式還嘗試在適當的位置使用sorted()
。例如,此塊L = list(some_iterable) L.sort()
將更改為
L = sorted(some_iterable)
- import¶
檢測同級匯入並將其轉換為相對匯入。
- imports¶
處理標準庫中的模組重新命名。
- input¶
將
input(prompt)
轉換為eval(input(prompt))
。
- intern¶
將
intern()
轉換為sys.intern()
。
- isinstance¶
修復
isinstance()
第二個引數中的重複型別。例如,isinstance(x, (int, int))
轉換為isinstance(x, int)
,isinstance(x, (int, float, int))
轉換為isinstance(x, (int, float))
。
- itertools_imports¶
刪除
itertools.ifilter()
、itertools.izip()
和itertools.imap()
的匯入。itertools.ifilterfalse()
的匯入也已更改為itertools.filterfalse()
。
- itertools¶
更改對
itertools.ifilter()
、itertools.izip()
和itertools.imap()
的使用,使其等效於其內建函式。將itertools.ifilterfalse()
更改為itertools.filterfalse()
。
- metaclass¶
將舊元類語法(類主體中的
__metaclass__ = Meta
)轉換為新語法(class X(metaclass=Meta)
)。
- methodattrs¶
修復舊方法屬性名稱。例如,將
meth.im_func
轉換為meth.__func__
。
- ne¶
將舊的不等於語法
<>
轉換為!=
。
- next¶
將迭代器的
next()
方法的使用轉換為next()
函式。還將next()
方法重新命名為__next__()
。
- nonzero¶
將名為
__nonzero__()
的方法的定義重新命名為__bool__()
。
- numliterals¶
將八進位制字面量轉換為新語法。
- operator¶
將
operator
模組中對各種函式的呼叫轉換為其他等效的函式呼叫。在需要時,會新增適當的import
語句,例如import collections.abc
。進行以下對映從
到
operator.isCallable(obj)
callable(obj)
operator.sequenceIncludes(obj)
operator.contains(obj)
operator.isSequenceType(obj)
isinstance(obj, collections.abc.Sequence)
operator.isMappingType(obj)
isinstance(obj, collections.abc.Mapping)
operator.isNumberType(obj)
isinstance(obj, numbers.Number)
operator.repeat(obj, n)
operator.mul(obj, n)
operator.irepeat(obj, n)
operator.imul(obj, n)
- paren¶
在列表解析中需要的地方新增額外的括號。例如,
[x for x in 1, 2]
變為[x for x in (1, 2)]
。
- raise¶
將
raise E, V
轉換為raise E(V)
,將raise E, V, T
轉換為raise E(V).with_traceback(T)
。如果E
是一個元組,則轉換將不正確,因為在 3.0 中已刪除將元組替換為異常的做法。
- reduce¶
處理
reduce()
移至functools.reduce()
。
- reload¶
將
reload()
轉換為importlib.reload()
。
- renames¶
將
sys.maxint
更改為sys.maxsize
。
- sys_exc¶
將已棄用的
sys.exc_value
、sys.exc_type
、sys.exc_traceback
更改為使用sys.exc_info()
。
- throw¶
修復生成器的
throw()
方法中的 API 更改。
- tuple_params¶
刪除隱式元組引數解包。此修復程式插入臨時變數。
- ws_comma¶
從逗號分隔項中移除多餘的空白。此修復程式是可選的。
- xreadlines¶
將
for x in file.xreadlines()
更改為for x in file
。
lib2to3
— 2to3 的庫¶
原始碼: Lib/lib2to3/
自 3.11 版本棄用,將在 3.13 版本中移除: Python 3.9 切換到了 PEG 解析器(參見 PEP 617),而 lib2to3 則使用靈活性較低的 LL(1) 解析器。Python 3.10 包含 lib2to3 的 LL(1) 解析器無法解析的新語言語法(參見 PEP 634)。lib2to3
模組在 Python 3.9 中被標記為待棄用(在匯入時引發 PendingDeprecationWarning
),並在 Python 3.11 中完全棄用(引發 DeprecationWarning
)。它將在 Python 3.13 中從標準庫中移除。考慮使用第三方替代方案,例如 LibCST 或 parso。
注意
lib2to3
API 應被視為不穩定,未來可能會發生巨大變化。