跳轉到

2008:Python 3.0 大分裂——print()、Unicode、真除法#

事件#

2008 年 12 月,Python 3.0 發佈——這是 Python 史上唯一一次「破壞性大版本」。語言創建者決定放棄向後相容,一次清償二十年累積的設計債:

  1. print 從陳述式變函式(PEP 3105):print("hello")
  2. Unicode str 成為預設字串型別,bytes 另立(PEP 3112 之後定型的 b"...")
  3. / 真除法:5/2 == 2.5(PEP 238,2.2 時已預告);整除改用 //
  4. 新式 metaclass 語法:class Foo(metaclass=Meta)(PEP 3115)
  5. 移除 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(藏在類別主體)

相關條目#