成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Python的51個“秘密”被曝光,GitHub獲2萬星

新聞 后端
Python,是一個設計優美的解釋型高級語言,它提供了很多能讓程序員感到舒適的功能特性。

 [[268605]]

Python,是一個設計優美的解釋型高級語言,它提供了很多能讓程序員感到舒適的功能特性。

但有的時候,Python一些特性導致的輸出結果,對于初學者就很難理解了。

一個解析51項堪稱是“秘密”的Python特性項目,在GitHub上徹底火了。

英文原版已經拿到了近15000星,中文翻譯版也獲得了7500+星。

Python的51個“秘密”被曝光,GitHub獲2萬星
Python的51個“秘密”被曝光,GitHub獲2萬星

項目中的部分內容,也許你聽說過,但依然可能會透露一些你所不知道的Python有趣特性。

我覺得這是學習編程語言內部原理的好機會,而且我相信你也會從中獲得樂趣!

如果你是一位經驗比較豐富的Python程序員,你可以試試能否一次就找到正確答案。

也許你對其中的一些例子比較熟悉,那這些案例能喚起你當年踩坑時的甜蜜回憶。

這個項目的中文版全文大約2萬字,干貨多的快要溢出來了,大家可以先看一下目錄。

Python的51個“秘密”被曝光,GitHub獲2萬星

示例結構

所有示例的結構都如下所示:

> 一個精選的標題

# 準備代碼.

# 釋放魔法...

Output (Python version):

>>> 觸發語句

出乎意料的輸出結果

(可選): 對意外輸出結果的簡短描述。

說明:

簡要說明發生了什么以及為什么會發生。

如有必要,舉例說明

Output:

>>>觸發語句#一些讓魔法變得容易理解的例子

#一些正常的輸入

注意:所有的示例都在Python3.5.2版本的交互解釋器上測試過,如果不特別說明應該適用于所有Python版本。

用法

我個人建議,最好依次閱讀下面的示例,并仔細閱讀設置例子最開始的代碼。

閱讀輸出結果

  • 確認結果是否如你所料.

  • 確認你是否知道這背后的原理

示例

微妙的字符串

1.

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

2.

  1. >>> a = "wtf" 
  2. >>> b = "wtf" 
  3. >>> a is b 
  4. True 
  5.  
  6. >>> a = "wtf!" 
  7. >>> b = "wtf!" 
  8. >>> a is b 
  9. False 
  10.  
  11. >>> a, b = "wtf!""wtf!" 
  12. >>> a is b 
  13. True 

3.

  1. >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' 
  2. True 
  3. >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa' 
  4. False 

說明:

這些行為是由于 Cpython 在編譯優化時,某些情況下會嘗試使用已經存在的不可變對象,而不是每次都創建一個新對象。(這種行為被稱作字符串的駐留[string interning])

發生駐留之后,許多變量可能指向內存中的相同字符串對象。(從而節省內存)

在上面的代碼中,字符串是隱式駐留的。何時發生隱式駐留則取決于具體的實現。這里有一些方法可以用來猜測字符串是否會被駐留:

所有長度為 0 和長度為 1 的字符串都被駐留。

字符串在編譯時被實現。('wtf' 將被駐留, 但是 ''.join(['w', 't', 'f'] 將不會被駐留)

字符串中只包含字母,數字或下劃線時將會駐留。所以 'wtf!' 由于包含!而未被駐留。可以在這里找CPython對此規則的實現。

Python的51個“秘密”被曝光,GitHub獲2萬星

當在同一行將 a 和 b 的值設置為 "wtf!" 的時候, Python 解釋器會創建一個新對象, 然后同時引用第二個變量。

如果你在不同的行上進行賦值操作, 它就不會“知道”已經有一個 wtf! 對象 (因為 "wtf!" 不是按照上面提到的方式被隱式駐留的)。

它是一種編譯器優化,特別適用于交互式環境。

常量折疊(constant folding) 是 Python 中的一種窺孔優化(peephole optimization) 技術。

這意味著在編譯時表達式 'a'*20 會被替換為 'aaaaaaaaaaaaaaaaaaaa' 以減少運行時的時鐘周期。

只有長度小于 20 的字符串才會發生常量折疊。(為啥? 想象一下由于表達式'a'*10**10 而生成的 .pyc 文件的大小)相關的源碼:

https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288

是時候來點蛋糕了!

1.

  1. some_dict = {} 
  2. some_dict[5.5] = "Ruby" 
  3. some_dict[5.0] = "JavaScript" 
  4. some_dict[5] = "Python" 
  5.  
  6. Output: 
  7.  
  8. >>> some_dict[5.5
  9. "Ruby" 
  10. >>> some_dict[5.0
  11. "Python" 
  12. >>> some_dict[5
  13. "Python" 
  14.  
  15. "Python" 消除了 "JavaScript" 的存在? 

說明:

Python 字典通過檢查鍵值是否相等和比較哈希值來確定兩個鍵是否相同。

具有相同值的不可變對象在Python中始終具有相同的哈希值。

  1. >>> 5 == 5.0 
  2. True 
  3. >>> hash(5) == hash(5.0
  4. True 

注意: 具有不同值的對象也可能具有相同的哈希值(哈希沖突)。

當執行 some_dict[5] = "Python" 語句時, 因為Python將 5 和 5.0 識別為 some_dict 的同一個鍵, 所以已有值 "JavaScript" 就被 "Python" 覆蓋了。

到處返回!

  1. def some_func(): 
  2. try
  3. return 'from_try' 
  4. finally
  5. return 'from_finally' 
  6.  
  7. Output: 
  8.  
  9. >>> some_func() 
  10.  
  11. 'from_finally' 

說明:

當在 "try...finally" 語句的 try 中執行 return, break 或 continue 后, finally 子句依然會執行。

函數的返回值由最后執行的 return 語句決定。

由于 finally 子句一定會執行, 所以 finally 子句中的 return 將始終是最后執行的語句。

本質上,我們都一樣

  1. class WTF: 
  2. pass 
  3.  
  4. Output: 
  5.  
  6. >>> WTF() == WTF() # 兩個不同的對象應該不相等 
  7.  
  8. False 
  9.  
  10. >>> WTF() is WTF() # 也不相同 
  11.  
  12. False 
  13.  
  14. >>> hash(WTF()) == hash(WTF()) # 哈希值也應該不同 
  15.  
  16. True 
  17.  
  18. >>> id(WTF()) == id(WTF()) 
  19.  
  20. True 

說明:

當調用 id 函數時, Python 創建了一個 WTF 類的對象并傳給 id 函數。

然后 id 函數獲取其id值 (也就是內存地址), 然后丟棄該對象. 該對象就被銷毀了。

當我們連續兩次進行這個操作時, Python會將相同的內存地址分配給第二個對象。 因為 (在CPython中) id 函數使用對象的內存地址作為對象的id值, 所以兩個對象的id值是相同的。

綜上, 對象的id值僅僅在對象的生命周期內唯一。在對象被銷毀之后, 或被創建之前, 其他對象可以具有相同的id值。

那為什么 is 操作的結果為 False 呢? 讓我們看看這段代碼:

  1. class WTF(object): 
  2. def __init__(self): print("I"
  3. def __del__(self): print("D"
  4.  
  5. Output: 
  6.  
  7. >>> WTF() is WTF() 
  8. False 
  9. >>> id(WTF()) == id(WTF()) 
  10. True 

正如你所看到的, 對象銷毀的順序是造成所有不同之處的原因。

為什么?

  1. some_string = "wtf" 
  2. some_dict = {} 
  3. for i, some_dict[i] in enumerate(some_string): 
  4. pass 
  5.  
  6. Output: 
  7.  
  8. >>> some_dict # 創建了索引字典. 
  9. {0'w'1't'2'f'

說明:

Python 語法 中對 for 的定義是:

  1. for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] 

其中 exprlist 指分配目標. 這意味著對可迭代對象中的每一項都會執行類似 {exprlist} = {next_value} 的操作。

一個有趣的例子說明了這一點:

  1. for i in range(4): 
  2. print(i) 
  3. i = 10 
  4.  
  5. Output: 
  6.  
  7. 0 
  8. 1 
  9. 2 
  10. 3 

你可曾覺得這個循環只會運行一次?

說明:

由于循環在Python中工作方式, 賦值語句 i = 10 并不會影響迭代循環, 在每次迭代開始之前, 迭代器(這里指 range(4)) 生成的下一個元素就被解包并賦值給目標列表的變量(這里指 i)了。

在每次迭代中, enumerate(some_string) 函數就生成一個新值 i (計數器增加) 并從 some_string 中獲取一個字符。

然后將字典 some_dict 鍵 i (剛剛分配的) 的值設為該字符。本例中循環的展開可以簡化為:

  1. >>> i, some_dict[i] = (0'w'
  2. >>> i, some_dict[i] = (1't'
  3. >>> i, some_dict[i] = (2'f'
  4. >>> some_dict 

執行時機差異

1.

  1. array = [1815
  2. g = (x for x in array if array.count(x) > 0
  3. array = [2822
  4.  
  5. Output: 
  6.  
  7. >>> print(list(g)) 
  8. [8

2.

  1. array_1 = [1,2,3,4
  2. g1 = (x for x in array_1) 
  3. array_1 = [1,2,3,4,5
  4.  
  5. array_2 = [1,2,3,4
  6. g2 = (x for x in array_2) 
  7. array_2[:] = [1,2,3,4,5
  8.  
  9. Output: 
  10.  
  11. >>> print(list(g1)) 
  12. [1,2,3,4
  13.  
  14. >>> print(list(g2)) 
  15. [1,2,3,4,5

說明:

在生成器表達式中, in 子句在聲明時執行, 而條件子句則是在運行時執行。

所以在運行前, array 已經被重新賦值為 [2, 8, 22], 因此對于之前的 1, 8 和 15, 只有 count(8) 的結果是大于 0 的, 所以生成器只會生成 8。

第二部分中 g1 和 g2 的輸出差異則是由于變量 array_1 和 array_2 被重新賦值的方式導致的。

在第一種情況下, array_1 被綁定到新對象 [1,2,3,4,5], 因為 in 子句是在聲明時被執行的,所以它仍然引用舊對象 [1,2,3,4](并沒有被銷毀)。

在第二種情況下, 對 array_2 的切片賦值將相同的舊對象 [1,2,3,4] 原地更新為 [1,2,3,4,5]。

因此 g2 和 array_2 仍然引用同一個對象(這個對象現在已經更新為 [1,2,3,4,5])。

本文內容來自中文版項目,項目全文2萬多字,以及海量代碼。

因為篇幅原因,小七就只為大家展示這6個案例了,更多案例大家可以在項目中查看。

項目作者:Satwik Kansal

英文版項目名稱:wtfpython

中文版作者:慕晨

中文項目名稱:wtfpython-cn

因為平臺規定,無法放鏈接。大家可以自行搜索。

 

責任編輯:張燕妮 來源: 頭條科技
相關推薦

2021-05-17 09:44:34

程序員技能開發者

2025-01-06 08:50:00

GitHub開源項目

2023-07-28 14:26:06

特斯拉駕駛

2022-08-04 18:58:18

Github惡意軟件攻擊

2019-08-09 18:08:13

程序員技能開發者

2021-08-18 15:49:10

FBI恐怖分子信息泄露

2019-04-28 09:36:11

GitHub代碼開發者

2022-05-19 16:36:13

信息泄露隱私

2021-09-14 10:42:00

數據安全可穿戴設備網絡安全

2022-03-31 18:41:10

數據泄露

2021-08-09 15:56:43

機器學習人工智能計算機

2025-04-23 10:56:52

2024-03-04 19:14:15

2024-08-28 16:11:07

2020-07-02 15:00:28

GitHub代碼開發者

2024-04-08 11:28:14

2021-02-03 09:41:27

春節電腦程序員

2020-08-12 15:19:05

GitHub代碼開發者

2020-05-19 14:27:10

GitHubPythonAI算法

2021-04-09 16:25:00

GitHub代碼開發者
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91av在线看| 国产亚洲精品a | 成人影院网站ww555久久精品 | 国产精品高清一区二区三区 | www.五月婷婷.com | 国产a区 | 在线91| a久久久久久 | 一级片av| 国产最新精品视频 | 亚洲性网 | 久久精品免费一区二区三 | 久久五月婷 | 精品中文字幕在线 | 国产精品久久久久久久久免费高清 | 99福利在线观看 | 亚洲精品www| 日韩成人精品一区 | 国产精品爱久久久久久久 | 成人超碰在线 | 二区三区在线观看 | 99久久免费观看 | 午夜小视频免费观看 | 欧美成人一区二区三区片免费 | 国内精品免费久久久久软件老师 | 中文字幕av免费 | 在线观看成人 | 中文字幕视频一区二区 | 国产视频黄色 | 亚洲欧美久久 | 成人影院av | 日韩二区 | 国产91精品久久久久久久网曝门 | 日韩免费网站 | 中文字幕在线一区 | 中文字幕精品一区二区三区在线 | 国产精品高潮呻吟久久久久 | 亚洲久草| 成人av一区二区三区 | 日韩成人在线播放 | 成人黄页在线观看 |