2008:Python 3.0 大分裂——print()、Unicode、真除法#
事件#
2008 年 12 月,Python 3.0 發佈——這是 Python 史上唯一一次「破壞性大版本」。語言創建者決定放棄向後相容,一次清償二十年累積的設計債:
print從陳述式變函式(PEP 3105):print("hello")- Unicode
str成為預設字串型別,bytes 另立(PEP 3112 之後定型的b"...") /真除法:5/2 == 2.5(PEP 238,2.2 時已預告);整除改用//- 新式 metaclass 語法:
class Foo(metaclass=Meta)(PEP 3115) - 移除
reduce、舊式類別、<>運算子等歷史遺跡
為何重要#
- 2/3 分裂的代價:Python 生態花了約十年(2008–2018,直到 Python 2 於 2020 年 1 月正式終止支援)才完成遷移。這是程式語言史上最大的生態遷移之一,也成為後世語言(如 Go 2、Perl 6/Raku)設計版本策略時的反面教材。
- 但清償的債是真實的:Python 2 的字串型別(ASCII str + 隱式編碼轉換)是無數亂碼與 UnicodeDecodeError 的根源;
5/2 == 2違反數學直覺,是科學計算的隱形炸彈。
理論與實用原因#
- 理論原因(print 變函式):陳述式無法被當作值傳遞(
map(print, xs)不可能)、無法被sep/end/file參數化擴充。把副作用操作函式化是函式式程式設計「副作用也是值」理論的實踐。 - 理論原因(Unicode 預設):字元編碼的正確模型是「文字 = Unicode 碼位序列,位元組 = 原始二進位」,兩者不可混用。Python 2 的
str(bytes)+unicode+ 隱式轉換違反此模型;Python 3 把「明確勝於隱含」(The Zen of Python)貫徹到字串層。 - 理論原因(真除法):
5/2 == 2對科學用戶(Python 的核心受眾之一)違反數學。這是 PEP 238 早在 2001 年就提出的修正。 - 實用原因:Python 2 累積的歷史包袱已讓「教學、科學、國際化」三大場景持續出錯;社群判斷「長痛不如短痛」。
彌補了什麼缺陷#
彌補了 Python 2「隱式編碼轉換導致亂碼、整數除法違反數學、print 不可組合、舊式/新式類別並存」的多重歷史缺陷。
程式範例#
四大清償,前後對比:
# 1. print:陳述式 → 函式
print "hello" # 2.x:不可組合、不可傳遞
print("hello", file=sys.stderr) # 3.x:參數化、可當值傳遞
list(map(print, ["a", "b"])) # 3.x 才可能:副作用操作函式化
# 2. Unicode 為預設:明確勝於隱含
s = "中文" # 3.x:str = Unicode 碼位序列
b = s.encode("utf-8") # b"\xe4\xb8\xad\xe6\x96\x87":bytes 是原始位元組
b.decode("utf-8") # 明確轉換——2.x 的隱式轉換是亂碼之源
# 3. 真除法:科學計算的正確答案
5 / 2 # 2.x: 2(違反數學直覺) 3.x: 2.5
5 // 2 # 3.x: 2(整除改用 //)
# 4. 新式 metaclass 語法(PEP 3115)
class Meta(type): pass
class Foo(metaclass=Meta): pass # 2.x: __metaclass__ = Meta(藏在類別主體)