1. 枚舉 - enumerate 可以有參數(shù)哦
之前我們這樣操作:
現(xiàn)在我們這樣操作:
enumerate函數(shù)還可以接收第二個參數(shù)阳谍。就像下面這樣:
2. 字典/集合 生成
你也許知道如何進行列表解析蛀柴,但是可能不知道字典/集合生成。它們簡單易用且高效。就像下面這個例子:
3. 強制浮點除法
4. 對Python表達式求值
我們都知道eval函數(shù)圣猎,但是我們知道literal_eval函數(shù)么?也許很多人都不知道吧》溃可以用這種操作:
來代替以下這種操作:
我相信對于大多數(shù)人來說這種形式是第一次看見,但是實際上這個在Python中已經存在很長時間了柳沙。
5. 字符串/數(shù)列 逆序
你可以用以下方法快速逆序排列數(shù)列:
這總方式也同樣適用于字符串的逆序:
6. 三元運算
三元運算是if-else 語句的快捷操作薄料,也被稱為條件運算。這里有幾個例子可以供你參考秒梳,它們可以讓你的代碼更加緊湊阴汇,更加美觀寞蚌。
7. Python里面如何拷貝一個對象
標準庫中的copy模塊提供了兩個方法來實現(xiàn)拷貝.一個方法是copy,它返回和參數(shù)包含內容一樣的對象.
有些時候,你希望對象中的屬性也被復制,可以使用deepcopy方法:
小編推薦一個學Python的學習裙227-435-450,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有很多干貨和技術分享
8. python中如何判斷對象相等
首先是C#中字符串的==和equal方法孕讳。
“==” :
對于內置值類型而言食寡, == 判斷兩個內存值是否相等。
對于用戶自定義的值類型而言(Struct), == 需要重載监右,否則不能使用。
對于引用類型而言异希,默認是同一引用才返回true健盒,但是系統(tǒng)重載了很多引用類型的 == (比如下文提到的string),所以c#中引用類型的比較并不建議使用 ==称簿。
“equals” :
對于值類型而言扣癣, 內存相等才返回true。
對于引用類型而言憨降,指向同一個引用才算相等父虑。
但是比較特殊的是字符串String,是一個特殊的引用型類型,在C#語言中授药,重載了string的equals()方法士嚎,使string對象用起來就像是值類型一樣。
python中的 ==
python中的對象包含三要素:id, type, value
id 用來標識唯一一個對象悔叽,type標識對象的類型莱衩,value用來設置對象的值。
is 判斷是否是一個對象娇澎,使用id來判斷的笨蚁。
== 是判斷a對象的值是否是b對象的值,默認調用它的__eq__方法趟庄。
9. 命名技巧
今天閱讀代碼括细,發(fā)現(xiàn)一個不錯的函數(shù)命名方式:
def?request(_argv):
就是把所有的參數(shù)前面都加上_下劃線,這樣你在函數(shù)體中戚啥,一眼就可以看出那些是局部變量奋单,那些是作為參數(shù)傳入的,類似把全局變量前面加上g猫十。
10. 開發(fā)者工具集錦
pydoc: 模塊可以根據(jù)源代碼中的docstrings為任何可導入模塊生成格式良好的文檔览濒。
doctest模塊:該模塊可以從源代碼或獨立文件的例子中抽取出測試用例呆盖。
unittest模塊:該模塊是一個全功能的自動化測試框架,該框架提供了對測試準備(test fixtures), 預定義測試集(predefined test suite)以及測試發(fā)現(xiàn)(test discovery)的支持匾七。
trace:模塊可以監(jiān)控Python執(zhí)行程序的方式絮短,同時生成一個報表來顯示程序的每一行執(zhí)行的次數(shù)江兢。這些信息可以用來發(fā)現(xiàn)未被自動化測試集所覆蓋的程序執(zhí)行路徑昨忆,也可以用來研究程序調用圖,進而發(fā)現(xiàn)模塊之間的依賴關系杉允。編寫并執(zhí)行測試可以發(fā)現(xiàn)絕大多數(shù)程序中的問題邑贴,Python使得debug工作變得更加簡單,這是因為在大部分情況下叔磷,Python都能夠將未被處理的錯誤打印到控制臺中拢驾,我們稱這些錯誤信息為traceback。如果程序不是在文本控制臺中運行的改基,traceback也能夠將錯誤信息輸出到日志文件或是消息對話框中繁疤。當標準的traceback無法提供足夠的信息時,可以使用cgitb 模塊來查看各級棧和源代碼上下文中的詳細信息秕狰,比如局部變量稠腊。cgitb模塊還能夠將這些跟蹤信息以HTML的形式輸出,用來報告web應用中的錯誤鸣哀。
pdb:該模塊可以顯示出程序在錯誤產生時的執(zhí)行路徑架忌,同時可以動態(tài)地調整對象和代碼進行調試。
profile, timeit: 開發(fā)者可以使用profile以及timit模塊來測試程序的速度我衬,找出程序中到底是哪里很慢叹放,進而對這部分代碼獨立出來進行調優(yōu)的工作。
compileall: Python程序是通過解釋器執(zhí)行的挠羔,解釋器的輸入是原有程序的字節(jié)碼編譯版本井仰。這個字節(jié)碼編譯版本可以在程序執(zhí)行時動態(tài)地生成,也可以在程序打包的時候就生成破加。compileall模塊可以處理程序打包的事宜糕档,它暴露出了打包相關的接口,該接口能夠被安裝程序和打包工具用來生成包含模塊字節(jié)碼的文件拌喉。同時速那,在開發(fā)環(huán)境中,compileall模塊也可以用來驗證源文件是否包含了語法錯誤尿背。
YAPF:Google開源的Python代碼格式化工具端仰。
iPDB: iPDB是一個極好的工具,我已經用它查出了很多匪夷所思的bug田藐。pip install ipdb 安裝該工具荔烧,然后在你的代碼中import ipdb; ipdb.set_trace()吱七,然后你會在你的程序運行時,獲得一個很好的交互式提示鹤竭。它每次執(zhí)行程序的一行并且檢查變量踊餐。
pycallgraph: 在一些場合,我使用pycallgraph來追蹤性能問題臀稚。它可以創(chuàng)建函數(shù)調用時間和次數(shù)的圖表吝岭。
objgraph: objgraph對于查找內存泄露非常有用。
11. Python代碼微優(yōu)化之加快查找
collections.OrderedDict類:
注意最后一個參數(shù):dict_setitem=dict.setitem吧寺。如果你仔細想就會感覺有道理窜管。將值關聯(lián)到鍵上,你只需要給__setitem__傳遞三個參數(shù):要設置的鍵稚机,與鍵關聯(lián)的值幕帆,傳遞給內建dict類的__setitem__類方法。等會赖条,好吧失乾,也許最后一個參數(shù)沒什么意義。 最后一個參數(shù)其實是將一個函數(shù)綁定到局部作用域中的一個函數(shù)上纬乍。具體是通過將dict.__setitem__賦值為參數(shù)的默認值碱茁。這里還有另一個例子:
這里我們做同樣的事情,把本來將會在內建命名空間中的對象綁定到局部作用域中去蕾额。因此早芭,python將會使用LOCAL_FAST而不是LOAD_GLOBAL(全局查找)。那么這到底有多快呢诅蝶?我們做個簡單的測試:
換句話說退个,大概有11.9%的提升 [2]。比我在文章開始處承諾的5%還多调炬!
12. 包管理
Python世界最棒的地方之一语盈,就是大量的第三方程序包。同樣缰泡,管理這些包也非常容易刀荒。按照慣例,會在 requirements.txt 文件中列出項目所需要的包棘钞。每個包占一行缠借,通常還包含版本號。
13. Python函數(shù)參數(shù)默認值的陷阱和原理深究
可見代碼運行結果并不和我們預期的一樣宜猜。list_2在函數(shù)的第二次調用時并沒有得到一個新的list并填入2泼返,而是在第一次調用結果的基礎上append了一個2。為什么會發(fā)生這樣在其他編程語言中簡直就是設計bug一樣的問題呢姨拥?
可見如果參數(shù)默認值是在函數(shù)編譯compile階段就已經被確定绅喉。之后所有的函數(shù)調用時渠鸽,如果參數(shù)不顯示的給予賦值,那么所謂的參數(shù)默認值不過是一個指向那個在compile階段就已經存在的對象的指針柴罐。如果調用函數(shù)時徽缚,沒有顯示指定傳入參數(shù)值得話。那么所有這種情況下的該參數(shù)都會作為編譯時創(chuàng)建的那個對象的一種別名存在革屠。如果參數(shù)的默認值是一個不可變(Imuttable)數(shù)值凿试,那么在函數(shù)體內如果修改了該參數(shù),那么參數(shù)就會重新指向另一個新的不可變值屠阻。而如果參數(shù)默認值是和本文最開始的舉例一樣红省,是一個可變對象(Muttable)额各,那么情況就比較糟糕了国觉。所有函數(shù)體內對于該參數(shù)的修改,實際上都是對compile階段就已經確定的那個對象的修改虾啦。
14. 單下劃線(_)
(1麻诀、在解釋器中:在這種情況下,“_”代表交互式解釋器會話中上一條執(zhí)行的語句的結果傲醉。這種用法首先被標準CPython解釋器采用蝇闭,然后其他類型的解釋器也先后采用。
(2硬毕、作為一個名稱:這與上面一點稍微有些聯(lián)系呻引,此時“”作為臨時性的名稱使用。這樣吐咳,當其他人閱讀你的代碼時將會知道逻悠,你分配了一個特定的名稱,但是并不會在后面再次用到該名稱韭脊。例如童谒,下面的例子中,你可能對循環(huán)計數(shù)中的實際值并不感興趣沪羔,此時就可以使用“”饥伊。
(3、國際化:也許你也曾看到”_“會被作為一個函數(shù)來使用蔫饰。這種情況下琅豆,它通常用于實現(xiàn)國際化和本地化字符串之間翻譯查找的函數(shù)名稱,這似乎源自并遵循相應的C約定篓吁。例如茫因,在Django文檔“轉換”章節(jié)中,你將能看到如下代碼:
可以發(fā)現(xiàn)越除,場景二和場景三中的使用方法可能會相互沖突节腐,所以我們需要避免在使用“”作為國際化查找轉換功能的代碼塊中同時使用“”作為臨時名稱外盯。
15. 名稱前的單下劃線(如:_shahriar)
程序員使用名稱前的單下劃線,用于指定該名稱屬性為“私有”翼雀。這有點類似于慣例饱苟,為了使其他人(或你自己)使用這些代碼時將會知道以“_”開頭的名稱只供內部使用。正如Python文檔中所述:
以下劃線 __ 為前綴的名稱(如_pam)應該被視為API中非公開的部分(不管是函數(shù)狼渊、方法還是數(shù)據(jù)成員)箱熬。此時,應該將它們看作是一種實現(xiàn)細節(jié)狈邑,在修改它們時無需對外部通知城须。
正如上面所說,這確實類似一種慣例米苹,因為它對解釋器來說確實有一定的意義糕伐,如果你寫了代碼 :?from <模塊/包名> import *?,那么以 _ 開頭的名稱都不會被導入蘸嘶,除非模塊或包中的?__all__?列表顯式地包含了它們良瞧。了解更多請查看?Importing * in Python
16. 名稱前的雙下劃線(如:__shahriar)
名稱(具體為一個方法名)前雙下劃線 _ 的用法并不是一種慣例,對解釋器來說它有特定的意義训唱。Python中的這種用法是為了避免與子類定義的名稱沖突褥蚯。Python文檔指出,__spam 這種形式(至少兩個前導下劃線况增,最多一個后續(xù)下劃線)的任何標識符將會被 正如所預料的赞庶,“_internal_use”并未改變,而“__method_name”卻被變成了“_ClassName__method_name”澳骤。此時歧强,如果你創(chuàng)建A的一個子類B,那么你將不能輕易地覆寫A中的方法“__method_name”宴凉。spam 這種形式原文取代誊锭,在這里 classname 是去掉前導下劃線的當前類名。例如下面的例子:
正如所預料的弥锄,“_internal_use”并未改變丧靡,而“__method_name”卻被變成了“_ClassName__method_name”。此時籽暇,如果你創(chuàng)建A的一個子類B温治,那么你將不能輕易地覆寫A中的方法“__method_name”。
17. 名稱前后的雙下劃線(如:init)
這種用法表示Python中特殊的方法名戒悠。其實熬荆,這只是一種慣例,對Python系統(tǒng)來說绸狐,這將確保不會與用戶自定義的名稱沖突卤恳。通常累盗,你將會覆寫這些方法,并在里面實現(xiàn)你所需要的功能突琳,以便Python調用它們若债。例如,當定義一個類時拆融,你經常會覆寫“init”方法蠢琳。
雖然你也可以編寫自己的特殊方法名,但不要這樣做镜豹。
18. 隱藏特性 1傲须,函數(shù)unpack
19. 隱藏特性 2, 鏈式比較操作符
20. 隱藏特性 3趟脂,函數(shù)的默認參數(shù)
更安全的做法是:
21. 隱藏特性 4泰讽,帶關鍵字的格式化
更新些的格式化:
22. 隱藏特性 5,切片操作的步長參數(shù)
可以用步長 -1 來反轉鏈表:
23. 隱藏特性 6散怖,嵌套列表推導式
列表推導構造permutation:可以用 itertools.permutations 來實現(xiàn)菇绵。
24. 隱藏特性 7肄渗,print 重定向輸出到文件
注意打開的模式: “w+” 而不能 “w” , 當然 “a” 是可以的
>>> print >> open("somefile", "w+"), "Hello World"
25. 隱藏特性 8镇眷, Python3中的元組unpack
26. 隱藏特性 9,pow的第三個參數(shù)
其實第三個參數(shù)是來求模的: pow(x, y, z) == (x ** y) % z翎嫡,注意欠动,內置的 pow 和 math.pow 并不是一個函數(shù),后者只接受2個參數(shù)惑申。
27. 隱藏特性 10具伍,enumerate還有第二個參數(shù)?
enumerate 很贊,可以給我們索引和序列值的對, 但是它還有第二個參數(shù)圈驼,這個參數(shù)用來: 指明索引的起始值人芽。
28. 隱藏特性 11,顯式的聲明一個集合
在Python 2.7 之后可以這么聲明一個集合绩脆。
29. 隱藏特性 12萤厅,用切片來刪除序列的某一段
當然用 del a[1:4] 也是可以的,去除偶數(shù)項(偶數(shù)索引的):
30. 隱藏特性 13靴迫,isinstance可以接收一個元組
這個真的鮮為人知, 我們可以用 isinstance(x, (float, int)) 來判斷 x 是不是數(shù)惕味,也就是那個元組里面是 或 的關系,只要是其中一個的實例就返回 True玉锌。
31. 讓關鍵代碼依賴于外部包
雖然Python讓許多編程任務變得容易名挥,但它可能并不總能為緊急的任務提供最佳性能毕贼。你可以為緊急的任務使用C闷旧、C++或機器語言編寫的外部包,這樣可以提高應用程序的性能。這些包都是不能跨平臺的枉氮,這意味著你需要根據(jù)你正在使用的平臺,尋找合適的包猛蔽。簡而言之善绎,這個方案放棄了一些應用程序的可移植性,以換取只有在特定主機上直接編程才能獲得的程序性能捎谨。這里有一些你應該考慮加入到你的“性能兵工廠”的包:
Cython
PyInlne
PyPy
Pyrex
這些包以不同的方式提高性能民效。例如,Pyrex能夠擴展Python所能做的事情涛救,例如使用C的數(shù)據(jù)類型來讓內存任務更加有效或直接畏邢。PyInIne讓你在Python應用程序中直接使用C代碼。程序中的內聯(lián)代碼單獨編譯检吆,但它在利用C語言所能提供的效率的同時舒萎,也讓所有的代碼都在同一個地方。
32. 排序時使用鍵(key)
有很多老的Python排序代碼蹭沛,它們在你創(chuàng)建一個自定義的排序時花費你的時間臂寝,但在運行時確實能加速執(zhí)行排序過程。元素排序的最好方法是盡可能使用鍵(key)和默認的sort()排序方法摊灭。例如咆贬,考慮下面的代碼:
每一個實例中,根據(jù)你選擇的作為key參數(shù)部分的索引帚呼,數(shù)組進行了排序掏缎。類似于利用數(shù)字進行排序,這種方法同樣適用于利用字符串排序煤杀。
33. 優(yōu)化循環(huán)
每種編程語言都會強調需要優(yōu)化循環(huán)眷蜈。當使用Python的時候,你可以依靠大量的技巧使得循環(huán)運行得更快沈自。然而酌儒,開發(fā)者經常漏掉的一個方法是:避免在一個循環(huán)中使用點操作。例如枯途,考慮下面的代碼:
每一次你調用方法str.upper忌怎,Python都會求該方法的值。然而柔袁,如果你用一個變量代替求得的值呆躲,值就變成了已知的,Python就可以更快地執(zhí)行任務捶索。優(yōu)化循環(huán)的關鍵插掂,是要減少Python在循環(huán)內部執(zhí)行的工作量,因為Python原生的解釋器在那種情況下,真的會減緩執(zhí)行的速度辅甥。
(注意:優(yōu)化循環(huán)的方法有很多酝润,這只是其中的一個。例如璃弄,許多程序員都會說要销,列表推導是在循環(huán)中提高執(zhí)行速度的最好方式。這里的關鍵是夏块,優(yōu)化循環(huán)是程序取得更高的執(zhí)行速度的更好方式之一疏咐。)
34. 嘗試多種編碼方法
如果每次你創(chuàng)建一個應用程序都是用相同的編碼方法,幾乎肯定會導致一些你的應用程序比它能夠達到的運行效率慢的情況脐供。作為分析過程的一部分浑塞,你可以嘗試一些實驗。例如政己,在一個字典中管理一些元素酌壕,你可以采用安全的方法確定元素是否已經存在并更新,或者你可以直接添加元素歇由,然后作為異常處理該元素不存在情況卵牍。考慮第一個編碼的例子:
這段代碼通常會在myDict開始為空時運行得更快沦泌。然而糊昙,當mydict通常被數(shù)據(jù)填充(或者至少大部分被充填)時,另一種方法效果更好赦肃。
兩種情況下具有相同的輸出:{‘d’: 4, ‘c’: 4, ‘b’: 4, ‘a’: 4}溅蛉。唯一的不同是這個輸出是如何得到的。跳出固定的思維模式他宛,創(chuàng)造新的編碼技巧,能夠幫助你利用你的應用程序獲得更快的結果欠气。
35. 使用列表推導式
一個列表推導式包含以下幾個部分:
一個輸入序列
一個表示輸入序列成員的變量
一個可選的斷言表達式
一個將輸入序列中滿足斷言表達式的成員變換成輸出列表成員的輸出表達式
而如果使用filter厅各、lambda和map函數(shù),則能夠將代碼大大簡化:
列表推導也可能會有一些負面效應预柒,那就是整個列表必須一次性加載于內存之中队塘,這對上面舉的例子而言不是問題,甚至擴大若干倍之后也都不是問題宜鸯。但是總會達到極限憔古,內存總會被用完。
針對上面的問題淋袖,生成器(Generator)能夠很好的解決鸿市。生成器表達式不會一次將整個列表加載到內存之中,而是生成一個生成器對象(Generator objector),所以一次只加載一個列表元素焰情。
生成器表達式同列表推導式有著幾乎相同的語法結構陌凳,區(qū)別在于生成器表達式是被圓括號包圍,而不是方括號:
這比列表推導效率稍微提高一些内舟,讓我們再一次改造一下代碼:
除非特殊的原因合敦,應該經常在代碼中使用生成器表達式。但除非是面對非常大的列表验游,否則是不會看出明顯區(qū)別的充岛。 再來看一個通過兩階列表推導式遍歷目錄的例子:
36. 裝飾器(Decorators)
裝飾器為我們提供了一個增加已有函數(shù)或類的功能的有效方法。聽起來是不是很像Java中的面向切面編程(Aspect-Oriented Programming)概念耕蝉?兩者都很簡單裸准,并且裝飾器有著更為強大的功能。舉個例子赔硫,假定你希望在一個函數(shù)的入口和退出點做一些特別的操作(比如一些安全炒俱、追蹤以及鎖定等操作)就可以使用裝飾器。
裝飾器是一個包裝了另一個函數(shù)的特殊函數(shù):主函數(shù)被調用爪膊,并且其返回值將會被傳給裝飾器权悟,接下來裝飾器將返回一個包裝了主函數(shù)的替代函數(shù),程序的其他部分看到的將是這個包裝函數(shù)推盛。
37. 上下文管理庫(ContextLib)
contextlib模塊包含了與上下文管理器和with聲明相關的工具峦阁。通常如果你想寫一個上下文管理器,則你需要定義一個類包含__enter__方法以及__exit__方法耘成,例如:
完整的例子在此:
上下文管理器被with聲明所激活榔昔,這個API涉及到兩個方法。
__enter__方法瘪菌,當執(zhí)行流進入with代碼塊時撒会,__enter__方法將執(zhí)行。并且它將返回一個可供上下文使用的對象师妙。
當執(zhí)行流離開with代碼塊時诵肛,__exit__方法被調用,它將清理被使用的資源默穴。
利用@contextmanager裝飾器改寫上面那個例子:
看上面這個例子怔檩,函數(shù)中yield之前的所有代碼都類似于上下文管理器中__enter__方法的內容。而yield之后的所有代碼都如__exit__方法的內容蓄诽。如果執(zhí)行過程中發(fā)生了異常薛训,則會在yield語句觸發(fā)。
38. 描述器(Deors)
描述器決定了對象屬性是如何被訪問的仑氛。描述器的作用是定制當你想引用一個屬性時所發(fā)生的操作乙埃。
構建描述器的方法是至少定義以下三個方法中的一個闸英。需要注意,下文中的instance是包含被訪問屬性的對象實例膊爪,而owner則是被描述器修辭的類自阱。
get(self, instance, owner) – 這個方法是當屬性被通過(value = obj.attr)的方式獲取時調用,這個方法的返回值將被賦給請求此屬性值的代碼部分米酬。?set(self, instance, value) – 這個方法是當希望設置屬性的值(obj.attr = ‘value’)時被調用沛豌,該方法不會返回任何值。?delete(self, instance) – 當從一個對象中刪除一個屬性時(del obj.attr)赃额,調用此方法加派。 譯者注:對于instance和owner的理解,考慮以下代碼:
39. Zipping and unzipping lists and iterables
40. Grouping adjacent list items using zip
41. Sliding windows (n-grams) using zip and iterators
42. Inverting a dictionary using zip
43. Flattening lists
44. Dictionary comprehensions
45. 常犯錯誤跳芳,濫用表達式作為函數(shù)參數(shù)默認值
Python允許開發(fā)者指定一個默認值給函數(shù)參數(shù)芍锦,雖然這是該語言的一個特征,但當參數(shù)可變時飞盆,很容易導致混亂娄琉,例如,下面這段函數(shù)定義:
在上面這段代碼里吓歇,一旦重復調用foo()函數(shù)(沒有指定一個bar參數(shù))孽水,那么將一直返回’bar’,因為沒有指定參數(shù)城看,那么foo()每次被調用的時候女气,都會賦予[]。下面來看看测柠,這樣做的結果:
解決方案:
46. 誤解Python規(guī)則范圍
Python的作用域解析是基于LEGB規(guī)則炼鞠,分別是Local、Enclosing轰胁、Global谒主、Built-in。實際上软吐,這種解析方法也有一些玄機瘩将,看下面這個例子:
許多人會感動驚訝,當他們在工作的函數(shù)體里添加一個參數(shù)語句凹耙,會在先前工作的代碼里報UnboundLocalError錯誤( 點擊這里查看更詳細描述)。 在使用列表時肠仪,開發(fā)者是很容易犯這種錯誤的肖抱,看看下面這個例子:
為什么foo2失敗而foo1運行正常? 答案與前面那個例子是一樣的异旧,但又有一些微妙之處意述。foo1沒有賦值給lst,而foo2賦值了。lst += [5]實際上就是lst = lst + [5]荤崇,試圖給lst賦值(因此拌屏,假設Python是在局部作用域里)。然而术荤,我們正在尋找指定給lst的值是基于lst本身倚喂,其實尚未確定。
47. 修改遍歷列表
在遍歷的時候瓣戚,對列表進行刪除操作端圈,這是很低級的錯誤。稍微有點經驗的人都不會犯子库。 對上面的代碼進行修改舱权,正確地執(zhí)行:
48. 合理使用copy與deepcopy
對于dict和list等數(shù)據(jù)結構的對象,直接賦值使用的是引用的方式仑嗅。而有些情況下需要復制整個對象宴倍,這時可以使用copy包里的copy和deepcopy,這兩個函數(shù)的不同之處在于后者是遞歸復制的仓技。效率也不一樣:(以下程序在ipython中運行)
timeit后面的-n表示運行的次數(shù)鸵贬,后兩行對應的是兩個timeit的輸出,下同浑彰。由此可見后者慢一個數(shù)量級恭理。
49. 合理使用生成器(generator)和yield
使用()得到的是一個generator對象,所需要的內存空間與列表的大小無關郭变,所以效率會高一些颜价。在具體應用上,比如set(i for i in range(100000))會比set([i for i in range(100000)])快诉濒。
但是對于需要循環(huán)遍歷的情況:
后者的效率反而更高周伦,但是如果循環(huán)里有break,用generator的好處是顯而易見的。yield也是用于創(chuàng)建generator:
50. 使用級聯(lián)比較x < y < z
x < y < z效率略高未荒,而且可讀性更好专挪。
51. while 1 比 while True 更快
while 1 比 while true快很多,原因是在python2.x中片排,True是一個全局變量寨腔,而非關鍵字。
52. 使用**而不是pow
53. 使用 cProfile, cStringIO 和 cPickle等用c實現(xiàn)相同功能(分別對應profile, StringIO, pickle)的包
由c實現(xiàn)的包率寡,速度快10倍以上迫卢!
54. 使用最佳的反序列化方式
下面比較了eval, cPickle, json方式三種對相應字符串反序列化的效率,可見json比cPickle快近3倍冶共,比eval快20多倍乾蛤。
55. 怎么才算精通python
這個問題比較難回答每界,我是看 怎么樣才算是精通 Python 這個知乎問答,按照自己的看法整理了一些觀點家卖。不要問我是按什么標準整理的眨层,我只能說,整理的這些點上荡,第一趴樱,在我看來都說得不錯;第二榛臼,我自己都會去按照這些點來看看自己離 “精通” python還有多遠伊佃。
熟悉語法以及原聲數(shù)據(jù)結構
熟悉基本實現(xiàn)中的性能特點,就是知道什么操作會慢
會使用profile以及基于profile的性能分析工具
會使用運行時編譯和靜態(tài)編譯的工具沛善。pypy航揉,numba,cython金刁,ctypes帅涂,original C/C++ extension
熟悉你所在領域的拓展庫,比如我尤蛮,科學計算方面的庫不要太多媳友,numpy衍生出來的一大堆大堆
了解基本的編譯過程,基本的操作系統(tǒng)知識(只要你C产捞、C++學的還行就可以了)
要想精通python醇锚,寫的代碼首先得pythonic
研讀牛B的開源代碼,在這過程中會遇到python的許多高階用法
理解裝飾器坯临,生成器焊唬,描述符,元類
掌握list comprehension看靠,
多用內置函數(shù):map赶促,reduce,filter挟炬,iter鸥滨,range,divmod谤祖,round婿滓,chr,enumerate粥喜,all空幻,any,slice容客,zip+
56. python 猴子補丁相關
python里有一個很奇妙的monkey patch秕铛,中文叫做猴子補丁,是指的是在運行時動態(tài)替換某些已加載的模塊的實現(xiàn)缩挑。第一次了解這個概念是在使用gevent的時候但两,需要把python自帶的socket,os等相關模塊的實現(xiàn)改變成異步形式供置,但同時不改動python的源代碼谨湘。