自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python的51個(gè)“秘密”被曝光,GitHub獲2萬(wàn)星

新聞 后端
Python,是一個(gè)設(shè)計(jì)優(yōu)美的解釋型高級(jí)語(yǔ)言,它提供了很多能讓程序員感到舒適的功能特性。

 [[268605]]

Python,是一個(gè)設(shè)計(jì)優(yōu)美的解釋型高級(jí)語(yǔ)言,它提供了很多能讓程序員感到舒適的功能特性。

但有的時(shí)候,Python一些特性導(dǎo)致的輸出結(jié)果,對(duì)于初學(xué)者就很難理解了。

一個(gè)解析51項(xiàng)堪稱是“秘密”的Python特性項(xiàng)目,在GitHub上徹底火了。

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

Python的51個(gè)“秘密”被曝光,GitHub獲2萬(wàn)星
Python的51個(gè)“秘密”被曝光,GitHub獲2萬(wàn)星

項(xiàng)目中的部分內(nèi)容,也許你聽(tīng)說(shuō)過(guò),但依然可能會(huì)透露一些你所不知道的Python有趣特性。

我覺(jué)得這是學(xué)習(xí)編程語(yǔ)言內(nèi)部原理的好機(jī)會(huì),而且我相信你也會(huì)從中獲得樂(lè)趣!

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

也許你對(duì)其中的一些例子比較熟悉,那這些案例能喚起你當(dāng)年踩坑時(shí)的甜蜜回憶。

這個(gè)項(xiàng)目的中文版全文大約2萬(wàn)字,干貨多的快要溢出來(lái)了,大家可以先看一下目錄。

Python的51個(gè)“秘密”被曝光,GitHub獲2萬(wàn)星

示例結(jié)構(gòu)

所有示例的結(jié)構(gòu)都如下所示:

> 一個(gè)精選的標(biāo)題

# 準(zhǔn)備代碼.

# 釋放魔法...

Output (Python version):

>>> 觸發(fā)語(yǔ)句

出乎意料的輸出結(jié)果

(可選): 對(duì)意外輸出結(jié)果的簡(jiǎn)短描述。

說(shuō)明:

簡(jiǎn)要說(shuō)明發(fā)生了什么以及為什么會(huì)發(fā)生。

如有必要,舉例說(shuō)明

Output:

>>>觸發(fā)語(yǔ)句#一些讓魔法變得容易理解的例子

#一些正常的輸入

注意:所有的示例都在Python3.5.2版本的交互解釋器上測(cè)試過(guò),如果不特別說(shuō)明應(yīng)該適用于所有Python版本。

用法

我個(gè)人建議,最好依次閱讀下面的示例,并仔細(xì)閱讀設(shè)置例子最開(kāi)始的代碼。

閱讀輸出結(jié)果

  • 確認(rèn)結(jié)果是否如你所料.

  • 確認(rèn)你是否知道這背后的原理

示例

微妙的字符串

1.

  1. >>> a = "some_string" 
  2. >>> id(a) 
  3. 140420665652016 
  4. >>> id("some" + "_" + "string"# 注意兩個(gè)的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 

說(shuō)明:

這些行為是由于 Cpython 在編譯優(yōu)化時(shí),某些情況下會(huì)嘗試使用已經(jīng)存在的不可變對(duì)象,而不是每次都創(chuàng)建一個(gè)新對(duì)象。(這種行為被稱作字符串的駐留[string interning])

發(fā)生駐留之后,許多變量可能指向內(nèi)存中的相同字符串對(duì)象。(從而節(jié)省內(nèi)存)

在上面的代碼中,字符串是隱式駐留的。何時(shí)發(fā)生隱式駐留則取決于具體的實(shí)現(xiàn)。這里有一些方法可以用來(lái)猜測(cè)字符串是否會(huì)被駐留:

所有長(zhǎng)度為 0 和長(zhǎng)度為 1 的字符串都被駐留。

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

字符串中只包含字母,數(shù)字或下劃線時(shí)將會(huì)駐留。所以 'wtf!' 由于包含!而未被駐留。可以在這里找CPython對(duì)此規(guī)則的實(shí)現(xiàn)。

Python的51個(gè)“秘密”被曝光,GitHub獲2萬(wàn)星

當(dāng)在同一行將 a 和 b 的值設(shè)置為 "wtf!" 的時(shí)候, Python 解釋器會(huì)創(chuàng)建一個(gè)新對(duì)象, 然后同時(shí)引用第二個(gè)變量。

如果你在不同的行上進(jìn)行賦值操作, 它就不會(huì)“知道”已經(jīng)有一個(gè) wtf! 對(duì)象 (因?yàn)?"wtf!" 不是按照上面提到的方式被隱式駐留的)。

它是一種編譯器優(yōu)化,特別適用于交互式環(huán)境。

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

這意味著在編譯時(shí)表達(dá)式 'a'*20 會(huì)被替換為 'aaaaaaaaaaaaaaaaaaaa' 以減少運(yùn)行時(shí)的時(shí)鐘周期。

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

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

是時(shí)候來(lái)點(diǎn)蛋糕了!

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" 的存在? 

說(shuō)明:

Python 字典通過(guò)檢查鍵值是否相等和比較哈希值來(lái)確定兩個(gè)鍵是否相同。

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

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

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

當(dāng)執(zhí)行 some_dict[5] = "Python" 語(yǔ)句時(shí), 因?yàn)镻ython將 5 和 5.0 識(shí)別為 some_dict 的同一個(gè)鍵, 所以已有值 "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' 

說(shuō)明:

當(dāng)在 "try...finally" 語(yǔ)句的 try 中執(zhí)行 return, break 或 continue 后, finally 子句依然會(huì)執(zhí)行。

函數(shù)的返回值由最后執(zhí)行的 return 語(yǔ)句決定。

由于 finally 子句一定會(huì)執(zhí)行, 所以 finally 子句中的 return 將始終是最后執(zhí)行的語(yǔ)句。

本質(zhì)上,我們都一樣

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

說(shuō)明:

當(dāng)調(diào)用 id 函數(shù)時(shí), Python 創(chuàng)建了一個(gè) WTF 類的對(duì)象并傳給 id 函數(shù)。

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

當(dāng)我們連續(xù)兩次進(jìn)行這個(gè)操作時(shí), Python會(huì)將相同的內(nèi)存地址分配給第二個(gè)對(duì)象。 因?yàn)?(在CPython中) id 函數(shù)使用對(duì)象的內(nèi)存地址作為對(duì)象的id值, 所以兩個(gè)對(duì)象的id值是相同的。

綜上, 對(duì)象的id值僅僅在對(duì)象的生命周期內(nèi)唯一。在對(duì)象被銷毀之后, 或被創(chuàng)建之前, 其他對(duì)象可以具有相同的id值。

那為什么 is 操作的結(jié)果為 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 

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

為什么?

  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 # 創(chuàng)建了索引字典. 
  9. {0'w'1't'2'f'

說(shuō)明:

Python 語(yǔ)法 中對(duì) for 的定義是:

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

其中 exprlist 指分配目標(biāo). 這意味著對(duì)可迭代對(duì)象中的每一項(xiàng)都會(huì)執(zhí)行類似 {exprlist} = {next_value} 的操作。

一個(gè)有趣的例子說(shuō)明了這一點(diǎn):

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

你可曾覺(jué)得這個(gè)循環(huán)只會(huì)運(yùn)行一次?

說(shuō)明:

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

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

然后將字典 some_dict 鍵 i (剛剛分配的) 的值設(shè)為該字符。本例中循環(huán)的展開(kāi)可以簡(jiǎn)化為:

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

執(zhí)行時(shí)機(jī)差異

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

說(shuō)明:

在生成器表達(dá)式中, in 子句在聲明時(shí)執(zhí)行, 而條件子句則是在運(yùn)行時(shí)執(zhí)行。

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

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

在第一種情況下, array_1 被綁定到新對(duì)象 [1,2,3,4,5], 因?yàn)?in 子句是在聲明時(shí)被執(zhí)行的,所以它仍然引用舊對(duì)象 [1,2,3,4](并沒(méi)有被銷毀)。

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

因此 g2 和 array_2 仍然引用同一個(gè)對(duì)象(這個(gè)對(duì)象現(xiàn)在已經(jīng)更新為 [1,2,3,4,5])。

本文內(nèi)容來(lái)自中文版項(xiàng)目,項(xiàng)目全文2萬(wàn)多字,以及海量代碼。

因?yàn)槠颍∑呔椭粸榇蠹艺故具@6個(gè)案例了,更多案例大家可以在項(xiàng)目中查看。

項(xiàng)目作者:Satwik Kansal

英文版項(xiàng)目名稱:wtfpython

中文版作者:慕晨

中文項(xiàng)目名稱:wtfpython-cn

因?yàn)槠脚_(tái)規(guī)定,無(wú)法放鏈接。大家可以自行搜索。

 

責(zé)任編輯:張燕妮 來(lái)源: 頭條科技
相關(guān)推薦

2021-05-17 09:44:34

程序員技能開(kāi)發(fā)者

2025-01-06 08:50:00

GitHub開(kāi)源項(xiàng)目

2022-08-04 18:58:18

Github惡意軟件攻擊

2019-04-28 09:36:11

GitHub代碼開(kāi)發(fā)者

2023-07-28 14:26:06

特斯拉駕駛

2019-08-09 18:08:13

程序員技能開(kāi)發(fā)者

2021-08-18 15:49:10

FBI恐怖分子信息泄露

2022-05-19 16:36:13

信息泄露隱私

2021-08-09 15:56:43

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2024-03-04 19:14:15

2025-04-23 10:56:52

2021-09-14 10:42:00

數(shù)據(jù)安全可穿戴設(shè)備網(wǎng)絡(luò)安全

2022-03-31 18:41:10

數(shù)據(jù)泄露

2020-07-02 15:00:28

GitHub代碼開(kāi)發(fā)者

2020-05-19 14:27:10

GitHubPythonAI算法

2020-08-12 15:19:05

GitHub代碼開(kāi)發(fā)者

2021-04-09 16:25:00

GitHub代碼開(kāi)發(fā)者

2024-04-08 11:28:14

2024-08-28 16:11:07

2019-09-27 15:21:03

GitHub代碼開(kāi)發(fā)者
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)