最近,發現了一個在GitHub關於Python的一個非常有趣的項目。

這個項目叫《What the f*ck Python!》,專門介紹 Python 裡面那些奇奇怪怪的語言坑。

標星超12000,不看不知道一看嚇一跳 (?`?Д?′)!!


這個有趣的項目意在收集 Python 中那些難以理解和反人類直覺的例子以及鮮為人知的功能特性, 並嘗試討論這些現象背後真正的原理!

雖然下面的有些例子並不一定會讓你覺得 WTFs, 但它們依然有可能會告訴你一些你所不知道的 Python 有趣特性. 我覺得這是一種學習編程語言內部原理的好辦法, 而且我相信你也會從中獲得樂趣!

——Satwik Kansal


我們來瞅瞅 為何如此優秀

舉個栗子,來看看第一節吧

Strings can be tricky sometimes/微妙的字元串

1.

>>> a = "some_string"
>>> id(a)
140420665652016
>>> id("some" + "_" + "string") # 注意兩個的id值是相同的.
140420665652016

2.

>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True

>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False

>>> a, b = "wtf!", "wtf!"
>>> a is b
True

3.

>>> a * 20 is aaaaaaaaaaaaaaaaaaaa
True
>>> a * 21 is aaaaaaaaaaaaaaaaaaaaa
False

然後是說明

  • 這些行為是由於 Cpython 在編譯優化時, 某些情況下會嘗試使用已經存在的不可變對象而不是每次都創建一個新對象. (這種行為被稱作字元串的駐留[string interning])
  • 發生駐留之後, 許多變數可能指向內存中的相同字元串對象. (從而節省內存)
  • 在上面的代碼中, 字元串是隱式駐留的. 何時發生隱式駐留則取決於具體的實現. 這裡有一些方法可以用來猜測字元串是否會被駐留:
  1. 所有長度為 0 和長度為 1 的字元串都被駐留
  2. 字元串在編譯時被實現 (wtf 將被駐留, 但是 .join([w, t, f] 將不會被駐留)
  3. 字元串中只包含字母,數字或下劃線時將會駐留. 所以 wtf! 由於包含 ! 而未被駐留. 可以在這裡找到 CPython 對此規則的實現

  • 當在同一行將 ab 的值設置為 "wtf!" 的時候, Python 解釋器會創建一個新對象, 然後同時引用第二個變數. 如果你在不同的行上進行賦值操作, 它就不會「知道」已經有一個 wtf! 對象 (因為 "wtf!" 不是按照上面提到的方式被隱式駐留的). 它是一種編譯器優化, 特別適用於互動式環境.
  • 常量摺疊(constant folding) 是 Python 中的一種 窺孔優化(peephole optimization) 技術. 這意味著在編譯時表達式 a*20會被替換為 aaaaaaaaaaaaaaaaaaaa 以減少運行時的時鐘週期. 只有長度小於 20 的字元串才會發生常量摺疊. (為啥? 想像一下由於表達式 a*10**10 而生成的 .pyc 文件的大小). 相關的源碼實現在這裡.

Time for some hash brownies!/是時候來點蛋糕了!

some_dict = {}
some_dict[5.5] = "Ruby"
some_dict[5.0] = "JavaScript"
some_dict[5] = "Python"

Output:

>>> some_dict[5.5]
"Ruby"
>>> some_dict[5.0]
"Python"
>>> some_dict[5]
"Python"

"Python" 消除了 "JavaScript" 的存在?

說明:

  • Python 字典通過檢查鍵值是否相等和比較哈希值來確定兩個鍵是否相同.
  • 具有相同值的不可變對象在Python中始終具有相同的哈希值.

>>> 5 == 5.0
True
>>> hash(5) == hash(5.0)
True

  • 注意: 具有不同值的對象也可能具有相同的哈希值(哈希衝突).
  • 當執行 some_dict[5] = "Python" 語句時, 因為Python將 55.0 識別為 some_dict 的同一個鍵, 所以已有值 "JavaScript" 就被 "Python" 覆蓋了.
  • 這個 StackOverflow的 回答 漂亮的解釋了這背後的基本原理.

怎麼樣,心動沒?

這個項目的主體構成部分就是示例,部分目錄:

這個項目的原作者,據說是一個名為Satwik Kansal的印度帥小哥,真的感謝這位「老司機」及中文翻譯者。

傳送門

中文版:

github.com/leisurelicht

英文原版:

github.com/satwikkansal
推薦閱讀:
相關文章