https://litaotao.github.io/python-materials
1. 枚舉 - enumerate 可以有參數(shù)哦
之前我們這樣操作:
i=0
foriteminiterable:
printi,item
i+=1
現(xiàn)在我們這樣操作:
fori,iteminenumerate(iterable):
printi,item
enumerate函數(shù)還可以接收第二個(gè)參數(shù)撒强。就像下面這樣:
>>>list(enumerate('abc'))
[(0,'a'),(1,'b'),(2,'c')]
>>>list(enumerate('abc',1))
[(1,'a'),(2,'b'),(3,'c')]
2. 字典/集合 解析
你也許知道如何進(jìn)行列表解析,但是可能不知道字典/集合解析。它們簡(jiǎn)單易用且高效幔托。就像下面這個(gè)例子:
my_dict={i:i*iforiinxrange(100)}
my_set={i*15foriinxrange(100)}
# There is only a difference of ':' in both
# 兩者的區(qū)別在于字典推導(dǎo)中有冒號(hào)
3. 強(qiáng)制浮點(diǎn)除法
from__future__importdivision
result=1/2
# print(result)
# 0.5
4. 對(duì)Python表達(dá)式求值
我們都知道eval函數(shù),但是我們知道literal_eval函數(shù)么淑仆?也許很多人都不知道吧削饵。可以用這種操作:
importast
my_list=ast.literal_eval(expr)
來代替以下這種操作:
expr="[1, 2, 3]"
my_list=eval(expr)
我相信對(duì)于大多數(shù)人來說這種形式是第一次看見揉燃,但是實(shí)際上這個(gè)在Python中已經(jīng)存在很長(zhǎng)時(shí)間了。
5. 字符串/數(shù)列 逆序
你可以用以下方法快速逆序排列數(shù)列:
>>>a=[1,2,3,4]
>>>a[::-1]
[4,3,2,1]
# This creates a new reversed list.
# If you want to reverse a list in place you can do:
a.reverse()
這總方式也同樣適用于字符串的逆序:
>>>foo="yasoob"
>>>foo[::-1]
'boosay'
6. 三元運(yùn)算
三元運(yùn)算是if-else 語句的快捷操作筋栋,也被稱為條件運(yùn)算炊汤。這里有幾個(gè)例子可以供你參考,它們可以讓你的代碼更加緊湊弊攘,更加美觀抢腐。
[on_true]if[expression]else[on_false]
x,y=50,25
small=xifx
7. Python里面如何拷貝一個(gè)對(duì)象
標(biāo)準(zhǔn)庫中的copy模塊提供了兩個(gè)方法來實(shí)現(xiàn)拷貝.一個(gè)方法是copy,它返回和參數(shù)包含內(nèi)容一樣的對(duì)象.
importcopy
new_list=copy.copy(existing_list)
有些時(shí)候,你希望對(duì)象中的屬性也被復(fù)制,可以使用deepcopy方法:
importcopy
new_list_of_dicts=copy.deepcopy(existing_list_of_dicts)
copy(x)
ShallowcopyoperationonarbitraryPythonobjects.
deepcopy(x,memo=None,_nil=[])
DeepcopyoperationonarbitraryPythonobjects.
8. python中如何判斷對(duì)象相等
首先是C#中字符串的==和equal方法。
“==”:
對(duì)于內(nèi)置值類型而言襟交,==判斷兩個(gè)內(nèi)存值是否相等迈倍。
對(duì)于用戶自定義的值類型而言(Struct),==需要重載捣域,否則不能使用啼染。
對(duì)于引用類型而言,默認(rèn)是同一引用才返回true焕梅,但是系統(tǒng)重載了很多引用類型的==(比如下文提到的string)迹鹅,所以c#中引用類型的比較并不建議使用 ==。
“equals”:
對(duì)于值類型而言贞言,內(nèi)存相等才返回true斜棚。
對(duì)于引用類型而言,指向同一個(gè)引用才算相等该窗。
但是比較特殊的是字符串String,是一個(gè)特殊的引用型類型弟蚀,在C#語言中,重載了string的equals()方法酗失,使string對(duì)象用起來就像是值類型一樣义钉。
python中的==
python中的對(duì)象包含三要素:id,type,value
id用來標(biāo)識(shí)唯一一個(gè)對(duì)象,type標(biāo)識(shí)對(duì)象的類型级零,value用來設(shè)置對(duì)象的值断医。
is判斷是否是一個(gè)對(duì)象滞乙,使用id來判斷的。
==是判斷a對(duì)象的值是否是b對(duì)象的值鉴嗤,默認(rèn)調(diào)用它的__eq__方法斩启。
9. 命名技巧
今天閱讀代碼,發(fā)現(xiàn)一個(gè)不錯(cuò)的函數(shù)命名方式:
defrequest(_argv):
就是把所有的參數(shù)前面都加上_下劃線醉锅,這樣你在函數(shù)體中兔簇,一眼就可以看出那些是局部變量,那些是作為參數(shù)傳入的硬耍,類似把全局變量前面加上g垄琐。
10. 開發(fā)者工具集錦
pydoc: 模塊可以根據(jù)源代碼中的docstrings為任何可導(dǎo)入模塊生成格式良好的文檔。
doctest模塊:該模塊可以從源代碼或獨(dú)立文件的例子中抽取出測(cè)試用例经柴。
unittest模塊:該模塊是一個(gè)全功能的自動(dòng)化測(cè)試框架狸窘,該框架提供了對(duì)測(cè)試準(zhǔn)備(test fixtures), 預(yù)定義測(cè)試集(predefined test suite)以及測(cè)試發(fā)現(xiàn)(test discovery)的支持。
trace:模塊可以監(jiān)控Python執(zhí)行程序的方式坯认,同時(shí)生成一個(gè)報(bào)表來顯示程序的每一行執(zhí)行的次數(shù)翻擒。這些信息可以用來發(fā)現(xiàn)未被自動(dòng)化測(cè)試集所覆蓋的程序執(zhí)行路徑,也可以用來研究程序調(diào)用圖牛哺,進(jìn)而發(fā)現(xiàn)模塊之間的依賴關(guān)系陋气。編寫并執(zhí)行測(cè)試可以發(fā)現(xiàn)絕大多數(shù)程序中的問題,Python使得debug工作變得更加簡(jiǎn)單引润,這是因?yàn)樵诖蟛糠智闆r下巩趁,Python都能夠?qū)⑽幢惶幚淼腻e(cuò)誤打印到控制臺(tái)中,我們稱這些錯(cuò)誤信息為traceback淳附。如果程序不是在文本控制臺(tái)中運(yùn)行的议慰,traceback也能夠?qū)㈠e(cuò)誤信息輸出到日志文件或是消息對(duì)話框中。當(dāng)標(biāo)準(zhǔn)的traceback無法提供足夠的信息時(shí)燃观,可以使用cgitb 模塊來查看各級(jí)棧和源代碼上下文中的詳細(xì)信息褒脯,比如局部變量。cgitb模塊還能夠?qū)⑦@些跟蹤信息以HTML的形式輸出缆毁,用來報(bào)告web應(yīng)用中的錯(cuò)誤。
pdb:該模塊可以顯示出程序在錯(cuò)誤產(chǎn)生時(shí)的執(zhí)行路徑到涂,同時(shí)可以動(dòng)態(tài)地調(diào)整對(duì)象和代碼進(jìn)行調(diào)試脊框。
profile, timeit: 開發(fā)者可以使用profile以及timit模塊來測(cè)試程序的速度,找出程序中到底是哪里很慢践啄,進(jìn)而對(duì)這部分代碼獨(dú)立出來進(jìn)行調(diào)優(yōu)的工作浇雹。
compileall: Python程序是通過解釋器執(zhí)行的,解釋器的輸入是原有程序的字節(jié)碼編譯版本屿讽。這個(gè)字節(jié)碼編譯版本可以在程序執(zhí)行時(shí)動(dòng)態(tài)地生成昭灵,也可以在程序打包的時(shí)候就生成吠裆。compileall模塊可以處理程序打包的事宜,它暴露出了打包相關(guān)的接口烂完,該接口能夠被安裝程序和打包工具用來生成包含模塊字節(jié)碼的文件试疙。同時(shí),在開發(fā)環(huán)境中抠蚣,compileall模塊也可以用來驗(yàn)證源文件是否包含了語法錯(cuò)誤祝旷。
YAPF:Google開源的Python代碼格式化工具。
iPDB: iPDB是一個(gè)極好的工具嘶窄,我已經(jīng)用它查出了很多匪夷所思的bug怀跛。pip install ipdb 安裝該工具,然后在你的代碼中import ipdb; ipdb.set_trace()柄冲,然后你會(huì)在你的程序運(yùn)行時(shí)吻谋,獲得一個(gè)很好的交互式提示。它每次執(zhí)行程序的一行并且檢查變量现横。
pycallgraph: 在一些場(chǎng)合漓拾,我使用pycallgraph來追蹤性能問題。它可以創(chuàng)建函數(shù)調(diào)用時(shí)間和次數(shù)的圖表长赞。
objgraph: objgraph對(duì)于查找內(nèi)存泄露非常有用晦攒。
11. Python代碼微優(yōu)化之加快查找
collections.OrderedDict類:
def__setitem__(self,key,value,dict_setitem=dict.__setitem__):
ifkeynotinself:
root=self.__root
last=root[0]
last[1]=root[0]=self.__map[key]=[last,root,key]
returndict_setitem(self,key,value)
注意最后一個(gè)參數(shù):dict_setitem=dict.setitem。如果你仔細(xì)想就會(huì)感覺有道理得哆。將值關(guān)聯(lián)到鍵上脯颜,你只需要給__setitem__傳遞三個(gè)參數(shù):要設(shè)置的鍵,與鍵關(guān)聯(lián)的值贩据,傳遞給內(nèi)建dict類的__setitem__類方法栋操。等會(huì),好吧饱亮,也許最后一個(gè)參數(shù)沒什么意義矾芙。 最后一個(gè)參數(shù)其實(shí)是將一個(gè)函數(shù)綁定到局部作用域中的一個(gè)函數(shù)上。具體是通過將dict.__setitem__賦值為參數(shù)的默認(rèn)值近上。這里還有另一個(gè)例子:
defnot_list_or_dict(value):
returnnot(isinstance(value,dict)orisinstance(value,list))
defnot_list_or_dict(value,_isinstance=isinstance,_dict=dict,_list=list):
returnnot(_isinstance(value,_dict)or_isinstance(value,_list))
這里我們做同樣的事情剔宪,把本來將會(huì)在內(nèi)建命名空間中的對(duì)象綁定到局部作用域中去。因此壹无,python將會(huì)使用LOCAL_FAST而不是LOAD_GLOBAL(全局查找)葱绒。那么這到底有多快呢岳悟?我們做個(gè)簡(jiǎn)單的測(cè)試:
$python-mtimeit-s'def not_list_or_dict(value): return not (isinstance(value, dict) or isinstance(value, list))''not_list_or_dict(50)'
1000000loops,bestof3:0.48usecperloop
$python-mtimeit-s'def not_list_or_dict(value, _isinstance=isinstance, _dict=dict, _list=list): return not (_isinstance(value, _dict) or _isinstance(value, _list))''not_list_or_dict(50)'
1000000loops,bestof3:0.423usecperloop
換句話說驶俊,大概有11.9%的提升 [2]。比我在文章開始處承諾的5%還多臼寄!
12. 包管理
Python世界最棒的地方之一岖是,就是大量的第三方程序包帮毁。同樣实苞,管理這些包也非常容易。按照慣例烈疚,會(huì)在 requirements.txt 文件中列出項(xiàng)目所需要的包黔牵。每個(gè)包占一行,通常還包含版本號(hào)胞得。
pelican==3.3
Markdown
pelican-extended-sitemap==1.0.0
13. Python函數(shù)參數(shù)默認(rèn)值的陷阱和原理深究
Python2.7.9(default,Dec192014,06:05:48)
[GCC4.2.1CompatibleAppleLLVM6.0(clang-600.0.56)]ondarwin
Type"help","copyright","credits"or"license"formoreinformation.
>>>defgenerate_new_list_with(my_list=[],element=None):
...my_list.append(element)
...returnmy_list
...
>>>list_1=generate_new_list_with(element=1)
>>>list_1
[1]
>>>list_2=generate_new_list_with(element=2)
>>>list_2
[1,2]
>>>
可見代碼運(yùn)行結(jié)果并不和我們預(yù)期的一樣荧止。list_2在函數(shù)的第二次調(diào)用時(shí)并沒有得到一個(gè)新的list并填入2,而是在第一次調(diào)用結(jié)果的基礎(chǔ)上append了一個(gè)2阶剑。為什么會(huì)發(fā)生這樣在其他編程語言中簡(jiǎn)直就是設(shè)計(jì)bug一樣的問題呢跃巡?
可見如果參數(shù)默認(rèn)值是在函數(shù)編譯compile階段就已經(jīng)被確定。之后所有的函數(shù)調(diào)用時(shí)牧愁,如果參數(shù)不顯示的給予賦值素邪,那么所謂的參數(shù)默認(rèn)值不過是一個(gè)指向那個(gè)在compile階段就已經(jīng)存在的對(duì)象的指針。如果調(diào)用函數(shù)時(shí)猪半,沒有顯示指定傳入?yún)?shù)值得話兔朦。那么所有這種情況下的該參數(shù)都會(huì)作為編譯時(shí)創(chuàng)建的那個(gè)對(duì)象的一種別名存在。如果參數(shù)的默認(rèn)值是一個(gè)不可變(Imuttable)數(shù)值磨确,那么在函數(shù)體內(nèi)如果修改了該參數(shù)沽甥,那么參數(shù)就會(huì)重新指向另一個(gè)新的不可變值。而如果參數(shù)默認(rèn)值是和本文最開始的舉例一樣乏奥,是一個(gè)可變對(duì)象(Muttable)摆舟,那么情況就比較糟糕了。所有函數(shù)體內(nèi)對(duì)于該參數(shù)的修改邓了,實(shí)際上都是對(duì)compile階段就已經(jīng)確定的那個(gè)對(duì)象的修改恨诱。
14. 單下劃線(_)
1、在解釋器中:在這種情況下骗炉,“_”代表交互式解釋器會(huì)話中上一條執(zhí)行的語句的結(jié)果照宝。這種用法首先被標(biāo)準(zhǔn)CPython解釋器采用,然后其他類型的解釋器也先后采用句葵。
>>>_Traceback(mostrecentcalllast):
File"",line1,in
NameError:name'_'isnotdefined
>>>42
>>>_
42
>>>'alright!'if_else':('
'alright!'
>>>_
'alright!'
2厕鹃、作為一個(gè)名稱:這與上面一點(diǎn)稍微有些聯(lián)系,此時(shí)“”作為臨時(shí)性的名稱使用乍丈。這樣熊响,當(dāng)其他人閱讀你的代碼時(shí)將會(huì)知道,你分配了一個(gè)特定的名稱诗赌,但是并不會(huì)在后面再次用到該名稱。例如秸弛,下面的例子中铭若,你可能對(duì)循環(huán)計(jì)數(shù)中的實(shí)際值并不感興趣洪碳,此時(shí)就可以使用“”。
n=42
for_inrange(n):
do_something()
3叼屠、國際化:也許你也曾看到”_“會(huì)被作為一個(gè)函數(shù)來使用瞳腌。這種情況下,它通常用于實(shí)現(xiàn)國際化和本地化字符串之間翻譯查找的函數(shù)名稱镜雨,這似乎源自并遵循相應(yīng)的C約定嫂侍。例如,在Django文檔“轉(zhuǎn)換”章節(jié)中荚坞,你將能看到如下代碼:
fromdjango.utils.translationimportugettextas_
fromdjango.httpimportHttpResponse
defmy_view(request):
output=_("Welcome to my site.")
returnHttpResponse(output)
可以發(fā)現(xiàn)挑宠,場(chǎng)景二和場(chǎng)景三中的使用方法可能會(huì)相互沖突,所以我們需要避免在使用“”作為國際化查找轉(zhuǎn)換功能的代碼塊中同時(shí)使用“”作為臨時(shí)名稱颓影。
15. 名稱前的單下劃線(如:_shahriar)
程序員使用名稱前的單下劃線各淀,用于指定該名稱屬性為“私有”。這有點(diǎn)類似于慣例诡挂,為了使其他人(或你自己)使用這些代碼時(shí)將會(huì)知道以“_”開頭的名稱只供內(nèi)部使用碎浇。正如Python文檔中所述:
以下劃線 __ 為前綴的名稱(如_pam)應(yīng)該被視為API中非公開的部分(不管是函數(shù)、方法還是數(shù)據(jù)成員)璃俗。此時(shí)奴璃,應(yīng)該將它們看作是一種實(shí)現(xiàn)細(xì)節(jié),在修改它們時(shí)無需對(duì)外部通知城豁。
正如上面所說苟穆,這確實(shí)類似一種慣例,因?yàn)樗鼘?duì)解釋器來說確實(shí)有一定的意義钮蛛,如果你寫了代碼 :from <模塊/包名> import *鞭缭,那么以 _ 開頭的名稱都不會(huì)被導(dǎo)入,除非模塊或包中的__all__列表顯式地包含了它們魏颓。了解更多請(qǐng)查看Importing * in Python
16. 名稱前的雙下劃線(如:__shahriar)
名稱(具體為一個(gè)方法名)前雙下劃線 _ 的用法并不是一種慣例岭辣,對(duì)解釋器來說它有特定的意義。Python中的這種用法是為了避免與子類定義的名稱沖突甸饱。Python文檔指出沦童,__spam 這種形式(至少兩個(gè)前導(dǎo)下劃線,最多一個(gè)后續(xù)下劃線)的任何標(biāo)識(shí)符將會(huì)被 正如所預(yù)料的叹话,“_internal_use”并未改變偷遗,而“__method_name”卻被變成了“_ClassName__method_name”。此時(shí)驼壶,如果你創(chuàng)建A的一個(gè)子類B氏豌,那么你將不能輕易地覆寫A中的方法“__method_name”。spam 這種形式原文取代热凹,在這里 classname 是去掉前導(dǎo)下劃線的當(dāng)前類名泵喘。例如下面的例子:
>>>classA(object):
...def_internal_use(self):
...pass
...def__method_name(self):
...pass
...
>>>dir(A())
['_A__method_name',...,'_internal_use']
正如所預(yù)料的泪电,“_internal_use”并未改變,而“__method_name”卻被變成了“_ClassName__method_name”纪铺。此時(shí)相速,如果你創(chuàng)建A的一個(gè)子類B,那么你將不能輕易地覆寫A中的方法“__method_name”鲜锚。
17. 名稱前后的雙下劃線(如:init)
這種用法表示Python中特殊的方法名突诬。其實(shí),這只是一種慣例芜繁,對(duì)Python系統(tǒng)來說旺隙,這將確保不會(huì)與用戶自定義的名稱沖突。通常浆洗,你將會(huì)覆寫這些方法催束,并在里面實(shí)現(xiàn)你所需要的功能,以便Python調(diào)用它們伏社。例如抠刺,當(dāng)定義一個(gè)類時(shí),你經(jīng)常會(huì)覆寫“init”方法摘昌。
雖然你也可以編寫自己的特殊方法名速妖,但不要這樣做。
17. 隱藏特性 1聪黎,函數(shù)unpack
deffoo(x,y):
printx,y
alist=[1,2]
adict={'x':1,'y':2}
foo(*alist)# 1, 2
foo(**adict)# 1, 2
18. 隱藏特性 2罕容, 鏈?zhǔn)奖容^操作符
>>>x=3
>>>1
True
>>>4>x>=3
True
19. 隱藏特性 3,函數(shù)的默認(rèn)參數(shù)
>>>deffoo(x=[]):
...x.append(1)
...printx
...
>>>foo()
[1]
>>>foo()
[1,1]
更安全的做法是:
>>>deffoo(x=None):
...ifxisNone:
...x=[]
...x.append(1)
...printx
...
>>>foo()
[1]
>>>foo()
[1]
>>>
20. 隱藏特性 4稿饰,字典的get方法
21. 隱藏特性 5锦秒,帶關(guān)鍵字的格式化
>>>print"Hello%(name)s !"%{'name':'James'}
HelloJames!
>>>print"I am years%(age)i years old"%{'age':18}
Iamyears18yearsold
更新些的格式化:
>>>print"Hello {name} !".format(name="James")
HelloJames!
22. 隱藏特性 6,切片操作的步長(zhǎng)參數(shù)
可以用步長(zhǎng) -1 來反轉(zhuǎn)鏈表:
>>>a=[1,2,3,4,5]
>>>a[::2]
[1,3,5]
>>>a[::-1]
[5,4,3,2,1]
>>>
23. 隱藏特性 7喉镰,嵌套列表推導(dǎo)式
[(i,j)foriinrange(3)forjinrange(i)]
[(1,0),(2,0),(2,1)]
列表推導(dǎo)構(gòu)造permutation:
可以用 itertools.permutations 來實(shí)現(xiàn)旅择。
In[47]:a='abcd'
In[48]:[i+j+kforiinaforjina.replace(i,'')forkina.replace(i,'').replace(j,'')]
Out[48]:
['abc',
'abd',
'acb',
'acd',
'adb',
'adc',
'bac',
'bad',
'bca',
'bcd',
'bda',
'bdc',
'cab',
'cad',
'cba',
'cbd',
'cda',
'cdb',
'dab',
'dac',
'dba',
'dbc',
'dca',
'dcb']
24. 隱藏特性 8,print 重定向輸出到文件
注意打開的模式: “w+” 而不能 “w” , 當(dāng)然 “a” 是可以的
>>>print>>open("somefile","w+"),"Hello World"
25. 隱藏特性 9侣姆, Python3中的元組unpack
>>>a,b,*rest=range(10)
>>>a
0
>>>b
1
>>>rest
[2,3,4,5,6,7,8,9]
>>>
>>>first,second,*rest,last=range(10)
>>>first
0
>>>second
1
>>>last
9
>>>rest
[2,3,4,5,6,7,8]
26. 隱藏特性 10生真,pow的第三個(gè)參數(shù)
其實(shí)第三個(gè)參數(shù)是來求模的: pow(x, y, z) == (x ** y) % z,注意捺宗,內(nèi)置的 pow 和 math.pow 并不是一個(gè)函數(shù)柱蟀,后者只接受2個(gè)參數(shù)。
>>>pow(4,2,2)
0
>>>pow(4,2,3)
1
27. 隱藏特性 11蚜厉,enumerate還有第二個(gè)參數(shù)?
enumerate 很贊长已,可以給我們索引和序列值的對(duì), 但是它還有第二個(gè)參數(shù),這個(gè)參數(shù)用來: 指明索引的起始值。
>>>lst=["a","b","c"]
>>>list(enumerate(lst,1))
[(1,'a'),(2,'b'),(3,'c')]
28. 隱藏特性 12痰哨,顯式的聲明一個(gè)集合
在Python 2.7 之后可以這么聲明一個(gè)集合胶果。
>>>{1,2,3}
set([1,2,3])
29. 隱藏特性 13,用切片來刪除序列的某一段
>>>a=[1,2,3,4,5,6,7]
>>>a[1:4]=[]
>>>a
[1,5,6,7]
當(dāng)然用 del a[1:4] 也是可以的斤斧,去除偶數(shù)項(xiàng)(偶數(shù)索引的):
>>>a=[0,1,2,3,4,5,6,7]
>>>dela[::2]
>>>a
[1,3,5,7]
30. 隱藏特性 14,isinstance可以接收一個(gè)元組
這個(gè)真的鮮為人知, 我們可以用 isinstance(x, (float, int)) 來判斷 x 是不是數(shù)霎烙,也就是那個(gè)元組里面是 或 的關(guān)系撬讽,只要是其中一個(gè)的實(shí)例就返回 True。
>>>isinstance(1,(float,int))
True
>>>isinstance(1.3,(float,int))
True
>>>isinstance("1.3",(float,int))
False
31. 讓關(guān)鍵代碼依賴于外部包
雖然Python讓許多編程任務(wù)變得容易悬垃,但它可能并不總能為緊急的任務(wù)提供最佳性能游昼。你可以為緊急的任務(wù)使用C、C++或機(jī)器語言編寫的外部包尝蠕,這樣可以提高應(yīng)用程序的性能烘豌。這些包都是不能跨平臺(tái)的,這意味著你需要根據(jù)你正在使用的平臺(tái)看彼,尋找合適的包廊佩。簡(jiǎn)而言之,這個(gè)方案放棄了一些應(yīng)用程序的可移植性靖榕,以換取只有在特定主機(jī)上直接編程才能獲得的程序性能标锄。這里有一些你應(yīng)該考慮加入到你的“性能兵工廠”的包:
Cython
PyInlne
PyPy
Pyrex
這些包以不同的方式提高性能。例如茁计,Pyrex能夠擴(kuò)展Python所能做的事情料皇,例如使用C的數(shù)據(jù)類型來讓內(nèi)存任務(wù)更加有效或直接。PyInIne讓你在Python應(yīng)用程序中直接使用C代碼星压。程序中的內(nèi)聯(lián)代碼單獨(dú)編譯践剂,但它在利用C語言所能提供的效率的同時(shí),也讓所有的代碼都在同一個(gè)地方娜膘。
32. 排序時(shí)使用鍵(key)
有很多老的Python排序代碼逊脯,它們?cè)谀銊?chuàng)建一個(gè)自定義的排序時(shí)花費(fèi)你的時(shí)間,但在運(yùn)行時(shí)確實(shí)能加速執(zhí)行排序過程劲绪。元素排序的最好方法是盡可能使用鍵(key)和默認(rèn)的sort()排序方法男窟。例如,考慮下面的代碼:
importoperator
somelist=[(1,5,8),(6,2,4),(9,7,5)]
somelist.sort(key=operator.itemgetter(0))
somelist
#Output = [(1, 5, 8), (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(1))
somelist
#Output = [(6, 2, 4), (1, 5, 8), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(2))
somelist
每一個(gè)實(shí)例中贾富,根據(jù)你選擇的作為key參數(shù)部分的索引歉眷,數(shù)組進(jìn)行了排序。類似于利用數(shù)字進(jìn)行排序颤枪,這種方法同樣適用于利用字符串排序汗捡。
33. 優(yōu)化循環(huán)
每種編程語言都會(huì)強(qiáng)調(diào)需要優(yōu)化循環(huán)。當(dāng)使用Python的時(shí)候,你可以依靠大量的技巧使得循環(huán)運(yùn)行得更快扇住。然而春缕,開發(fā)者經(jīng)常漏掉的一個(gè)方法是:避免在一個(gè)循環(huán)中使用點(diǎn)操作。例如艘蹋,考慮下面的代碼:
lowerlist=['this','is','lowercase']
upper=str.upper
upperlist=[]
append=upperlist.append
forwordinlowerlist:
append(upper(word))
print(upperlist)
#Output = ['THIS', 'IS', 'LOWERCASE']
每一次你調(diào)用方法str.upper锄贼,Python都會(huì)求該方法的值。然而女阀,如果你用一個(gè)變量代替求得的值宅荤,值就變成了已知的,Python就可以更快地執(zhí)行任務(wù)浸策。優(yōu)化循環(huán)的關(guān)鍵冯键,是要減少Python在循環(huán)內(nèi)部執(zhí)行的工作量,因?yàn)镻ython原生的解釋器在那種情況下庸汗,真的會(huì)減緩執(zhí)行的速度惫确。
(注意:優(yōu)化循環(huán)的方法有很多,這只是其中的一個(gè)蚯舱。例如改化,許多程序員都會(huì)說,列表推導(dǎo)是在循環(huán)中提高執(zhí)行速度的最好方式晓淀。這里的關(guān)鍵是所袁,優(yōu)化循環(huán)是程序取得更高的執(zhí)行速度的更好方式之一。)
34. 嘗試多種編碼方法
如果每次你創(chuàng)建一個(gè)應(yīng)用程序都是用相同的編碼方法凶掰,幾乎肯定會(huì)導(dǎo)致一些你的應(yīng)用程序比它能夠達(dá)到的運(yùn)行效率慢的情況燥爷。作為分析過程的一部分,你可以嘗試一些實(shí)驗(yàn)懦窘。例如前翎,在一個(gè)字典中管理一些元素,你可以采用安全的方法確定元素是否已經(jīng)存在并更新畅涂,或者你可以直接添加元素港华,然后作為異常處理該元素不存在情況∥缢ィ考慮第一個(gè)編碼的例子:
n=16
myDict={}
foriinrange(0,n):
char='abcd'[i%4]
ifcharnotinmyDict:
myDict[char]=0
myDict[char]+=1
print(myDict)
這段代碼通常會(huì)在myDict開始為空時(shí)運(yùn)行得更快立宜。然而,當(dāng)mydict通常被數(shù)據(jù)填充(或者至少大部分被充填)時(shí)臊岸,另一種方法效果更好橙数。
n=16
myDict={}
foriinrange(0,n):
char='abcd'[i%4]
try:
myDict[char]+=1
exceptKeyError:
myDict[char]=1
print(myDict)
兩種情況下具有相同的輸出:{‘d’: 4, ‘c’: 4, ‘b’: 4, ‘a(chǎn)’: 4}。唯一的不同是這個(gè)輸出是如何得到的帅戒。跳出固定的思維模式灯帮,創(chuàng)造新的編碼技巧,能夠幫助你利用你的應(yīng)用程序獲得更快的結(jié)果。
35. 使用列表推導(dǎo)式
一個(gè)列表推導(dǎo)式包含以下幾個(gè)部分:
一個(gè)輸入序列
一個(gè)表示輸入序列成員的變量
一個(gè)可選的斷言表達(dá)式
一個(gè)將輸入序列中滿足斷言表達(dá)式的成員變換成輸出列表成員的輸出表達(dá)式
num=[1,4,-5,10,-7,2,3,-1]
filtered_and_squared=[]
fornumberinnum:
ifnumber>0:
filtered_and_squared.append(number**2)
printfiltered_and_squared
# [1, 16, 100, 4, 9]
而如果使用filter钟哥、lambda和map函數(shù)迎献,則能夠?qū)⒋a大大簡(jiǎn)化:
num=[1,4,-5,10,-7,2,3,-1]
filtered_and_squared=map(lambdax:x**2,filter(lambdax:x>0,num))
printfiltered_and_squared
# [1, 16, 100, 4, 9]
## 更簡(jiǎn)化的一種寫法
num=[1,4,-5,10,-7,2,3,-1]
filtered_and_squared=[x**2forxinnumifx>0]
printfiltered_and_squared
# [1, 16, 100, 4, 9]
列表推導(dǎo)也可能會(huì)有一些負(fù)面效應(yīng),那就是整個(gè)列表必須一次性加載于內(nèi)存之中腻贰,這對(duì)上面舉的例子而言不是問題吁恍,甚至擴(kuò)大若干倍之后也都不是問題。但是總會(huì)達(dá)到極限银受,內(nèi)存總會(huì)被用完践盼。
針對(duì)上面的問題,生成器(Generator)能夠很好的解決宾巍。生成器表達(dá)式不會(huì)一次將整個(gè)列表加載到內(nèi)存之中,而是生成一個(gè)生成器對(duì)象(Generator objector)渔伯,所以一次只加載一個(gè)列表元素顶霞。
生成器表達(dá)式同列表推導(dǎo)式有著幾乎相同的語法結(jié)構(gòu),區(qū)別在于生成器表達(dá)式是被圓括號(hào)包圍锣吼,而不是方括號(hào):
num=[1,4,-5,10,-7,2,3,-1]
filtered_and_squared=(x**2forxinnumifx>0)
printfiltered_and_squared
# at 0x00583E18>
foriteminfiltered_and_squared:
printitem
# 1, 16, 100 4,9
這比列表推導(dǎo)效率稍微提高一些选浑,讓我們?cè)僖淮胃脑煲幌麓a:
num=[1,4,-5,10,-7,2,3,-1]
defsquare_generator(optional_parameter):
return(x**2forxinnumifx>optional_parameter)
printsquare_generator(0)
# at 0x004E6418>
# Option I
forkinsquare_generator(0):
printk
# 1, 16, 100, 4, 9
# Option II
g=list(square_generator(0))
printg
# [1, 16, 100, 4, 9]
除非特殊的原因,應(yīng)該經(jīng)常在代碼中使用生成器表達(dá)式玄叠。但除非是面對(duì)非常大的列表古徒,否則是不會(huì)看出明顯區(qū)別的。 再來看一個(gè)通過兩階列表推導(dǎo)式遍歷目錄的例子:
importos
deftree(top):
forpath,names,fnamesinos.walk(top):
forfnameinfnames:
yieldos.path.join(path,fname)
fornameintree('C:\Users\XXX\Downloads\Test'):
printname
36. 裝飾器(Decorators)
裝飾器為我們提供了一個(gè)增加已有函數(shù)或類的功能的有效方法读恃。聽起來是不是很像Java中的面向切面編程(Aspect-Oriented Programming)概念隧膘??jī)烧叨己芎?jiǎn)單,并且裝飾器有著更為強(qiáng)大的功能寺惫。舉個(gè)例子疹吃,假定你希望在一個(gè)函數(shù)的入口和退出點(diǎn)做一些特別的操作(比如一些安全、追蹤以及鎖定等操作)就可以使用裝飾器西雀。
裝飾器是一個(gè)包裝了另一個(gè)函數(shù)的特殊函數(shù):主函數(shù)被調(diào)用萨驶,并且其返回值將會(huì)被傳給裝飾器,接下來裝飾器將返回一個(gè)包裝了主函數(shù)的替代函數(shù)艇肴,程序的其他部分看到的將是這個(gè)包裝函數(shù)腔呜。
importtime
fromfunctoolsimportwraps
deftimethis(func):
'''
Decorator that reports the execution time.
'''
@wraps(func)
defwrapper(*args,**kwargs):
start=time.time()
result=func(*args,**kwargs)
end=time.time()
print(func.__name__,end-start)
returnresult
returnwrapper
@timethis
defcountdown(n):
whilen>0:
n-=1
countdown(100000)
# ('countdown', 0.006999969482421875)
37. 上下文管理庫(ContextLib)
contextlib模塊包含了與上下文管理器和with聲明相關(guān)的工具。通常如果你想寫一個(gè)上下文管理器再悼,則你需要定義一個(gè)類包含__enter__方法以及__exit__方法核畴,例如:
importtime
classdemo:
def__init__(self,label):
self.label=label
def__enter__(self):
self.start=time.time()
def__exit__(self,exc_ty,exc_val,exc_tb):
end=time.time()
print('{}: {}'.format(self.label,end-self.start))
完整的例子在此:
importtime
classdemo:
def__init__(self,label):
self.label=label
def__enter__(self):
self.start=time.time()
def__exit__(self,exc_ty,exc_val,exc_tb):
end=time.time()
print('{}: {}'.format(self.label,end-self.start))
withdemo('counting'):
n=10000000
whilen>0:
n-=1
# counting: 1.36000013351
上下文管理器被with聲明所激活,這個(gè)API涉及到兩個(gè)方法帮哈。
__enter__方法膛檀,當(dāng)執(zhí)行流進(jìn)入with代碼塊時(shí),__enter__方法將執(zhí)行。并且它將返回一個(gè)可供上下文使用的對(duì)象咖刃。
當(dāng)執(zhí)行流離開with代碼塊時(shí)泳炉,__exit__方法被調(diào)用,它將清理被使用的資源嚎杨。
利用@contextmanager裝飾器改寫上面那個(gè)例子:
fromcontextlibimportcontextmanager
importtime
@contextmanager
defdemo(label):
start=time.time()
try:
yield
finally:
end=time.time()
print('{}: {}'.format(label,end-start))
withdemo('counting'):
n=10000000
whilen>0:
n-=1
# counting: 1.32399988174
看上面這個(gè)例子花鹅,函數(shù)中yield之前的所有代碼都類似于上下文管理器中__enter__方法的內(nèi)容。而yield之后的所有代碼都如__exit__方法的內(nèi)容枫浙。如果執(zhí)行過程中發(fā)生了異常刨肃,則會(huì)在yield語句觸發(fā)。
38. 描述器(Descriptors)
描述器決定了對(duì)象屬性是如何被訪問的箩帚。描述器的作用是定制當(dāng)你想引用一個(gè)屬性時(shí)所發(fā)生的操作真友。
構(gòu)建描述器的方法是至少定義以下三個(gè)方法中的一個(gè)。需要注意紧帕,下文中的instance是包含被訪問屬性的對(duì)象實(shí)例盔然,而owner則是被描述器修辭的類。
get(self, instance, owner) – 這個(gè)方法是當(dāng)屬性被通過(value = obj.attr)的方式獲取時(shí)調(diào)用是嗜,這個(gè)方法的返回值將被賦給請(qǐng)求此屬性值的代碼部分愈案。set(self, instance, value) – 這個(gè)方法是當(dāng)希望設(shè)置屬性的值(obj.attr = ‘value’)時(shí)被調(diào)用,該方法不會(huì)返回任何值鹅搪。delete(self, instance) – 當(dāng)從一個(gè)對(duì)象中刪除一個(gè)屬性時(shí)(del obj.attr)站绪,調(diào)用此方法。 譯者注:對(duì)于instance和owner的理解丽柿,考慮以下代碼:
classCelsius(object):
def__init__(self,value=0.0):
self.value=float(value)
def__get__(self,instance,owner):
returnself.value
def__set__(self,instance,value):
self.value=float(value)
classTemperature(object):
celsius=Celsius()
temp=Temperature()
temp.celsius#calls Celsius.__get__
39. Zipping and unzipping lists and iterables
>>>a=[1,2,3]
>>>b=['a','b','c']
>>>z=zip(a,b)
>>>z
[(1,'a'),(2,'b'),(3,'c')]
>>>zip(*z)
[(1,2,3),('a','b','c')]
40. Grouping adjacent list items using zip
>>>a=[1,2,3,4,5,6]
>>># Using iterators
>>>group_adjacent=lambdaa,k:zip(*([iter(a)]*k))
>>>group_adjacent(a,3)
[(1,2,3),(4,5,6)]
>>>group_adjacent(a,2)
[(1,2),(3,4),(5,6)]
>>>group_adjacent(a,1)
[(1,),(2,),(3,),(4,),(5,),(6,)]
>>># Using slices
>>>fromitertoolsimportislice
>>>group_adjacent=lambdaa,k:zip(*(islice(a,i,None,k)foriinrange(k)))
>>>group_adjacent(a,3)
[(1,2,3),(4,5,6)]
>>>group_adjacent(a,2)
[(1,2),(3,4),(5,6)]
>>>group_adjacent(a,1)
[(1,),(2,),(3,),(4,),(5,),(6,)]
41. Sliding windows (n-grams) using zip and iterators
>>>fromitertoolsimportislice
>>>defn_grams(a,n):
...z=(islice(a,i,None)foriinrange(n))
...returnzip(*z)
...
>>>a=[1,2,3,4,5,6]
>>>n_grams(a,3)
[(1,2,3),(2,3,4),(3,4,5),(4,5,6)]
>>>n_grams(a,2)
[(1,2),(2,3),(3,4),(4,5),(5,6)]
>>>n_grams(a,4)
[(1,2,3,4),(2,3,4,5),(3,4,5,6)]
42. Inverting a dictionary using zip
>>>m={'a':1,'b':2,'c':3,'d':4}
>>>m.items()
[('a',1),('c',3),('b',2),('d',4)]
>>>zip(m.values(),m.keys())
[(1,'a'),(3,'c'),(2,'b'),(4,'d')]
>>>mi=dict(zip(m.values(),m.keys()))
>>>mi
{1:'a',2:'b',3:'c',4:'d'}
43. Flattening lists
>>>a=[[1,2],[3,4],[5,6]]
>>>list(itertools.chain.from_iterable(a))
[1,2,3,4,5,6]
>>>sum(a,[])
[1,2,3,4,5,6]
>>>[xforlinaforxinl]
[1,2,3,4,5,6]
>>>a=[[[1,2],[3,4]],[[5,6],[7,8]]]
>>>[xforl1inaforl2inl1forxinl2]
[1,2,3,4,5,6,7,8]
>>>a=[1,2,[3,4],[[5,6],[7,8]]]
>>>flatten=lambdax:[yforlinxforyinflatten(l)]iftype(x)islistelse[x]
>>>flatten(a)
[1,2,3,4,5,6,7,8]
44. Dictionary comprehensions
>>>m={x:x**2forxinrange(5)}
>>>m
{0:0,1:1,2:4,3:9,4:16}
>>>m={x:'A'+str(x)forxinrange(10)}
>>>m
{0:'A0',1:'A1',2:'A2',3:'A3',4:'A4',5:'A5',6:'A6',7:'A7',8:'A8',9:'A9'}
45. 常犯錯(cuò)誤恢准,濫用表達(dá)式作為函數(shù)參數(shù)默認(rèn)值
Python允許開發(fā)者指定一個(gè)默認(rèn)值給函數(shù)參數(shù),雖然這是該語言的一個(gè)特征航厚,但當(dāng)參數(shù)可變時(shí)顷歌,很容易導(dǎo)致混亂,例如幔睬,下面這段函數(shù)定義:
>>>deffoo(bar=[]):# bar is optional and defaults to [] if not specified
...bar.append("baz")# but this line could be problematic, as we'll see...
...returnbar
在上面這段代碼里眯漩,一旦重復(fù)調(diào)用foo()函數(shù)(沒有指定一個(gè)bar參數(shù)),那么將一直返回’bar’麻顶,因?yàn)闆]有指定參數(shù)赦抖,那么foo()每次被調(diào)用的時(shí)候,都會(huì)賦予[]辅肾。下面來看看队萤,這樣做的結(jié)果:
>>>foo()
["baz"]
>>>foo()
["baz","baz"]
>>>foo()
["baz","baz","baz"]
解決方案:
>>>deffoo(bar=None):
...ifbarisNone:# or if not bar:
...bar=[]
...bar.append("baz")
...returnbar
...
>>>foo()
["baz"]
>>>foo()
["baz"]
>>>foo()
["baz"]
46. 誤解Python規(guī)則范圍
Python的作用域解析是基于LEGB規(guī)則,分別是Local矫钓、Enclosing要尔、Global舍杜、Built-in。實(shí)際上赵辕,這種解析方法也有一些玄機(jī)既绩,看下面這個(gè)例子:
>>>x=10
>>>deffoo():
...x+=1
...printx
...
>>>foo()
Traceback(mostrecentcalllast):
File"",line1,in
File"",line2,infoo
UnboundLocalError:localvariable'x'referencedbeforeassignment
許多人會(huì)感動(dòng)驚訝,當(dāng)他們?cè)诠ぷ鞯暮瘮?shù)體里添加一個(gè)參數(shù)語句还惠,會(huì)在先前工作的代碼里報(bào)UnboundLocalError錯(cuò)誤( 點(diǎn)擊這里查看更詳細(xì)描述)饲握。 在使用列表時(shí),開發(fā)者是很容易犯這種錯(cuò)誤的蚕键,看看下面這個(gè)例子:
>>>lst=[1,2,3]
>>>deffoo1():
...lst.append(5)# This works ok...
...
>>>foo1()
>>>lst
[1,2,3,5]
>>>lst=[1,2,3]
>>>deffoo2():
...lst+=[5]# ... but this bombs!
...
>>>foo2()
Traceback(mostrecentcalllast):
File"",line1,in
File"",line2,infoo
UnboundLocalError:localvariable'lst'referencedbeforeassignment
為什么foo2失敗而foo1運(yùn)行正常救欧? 答案與前面那個(gè)例子是一樣的,但又有一些微妙之處锣光。foo1沒有賦值給lst笆怠,而foo2賦值了。lst += [5]實(shí)際上就是lst = lst + [5]誊爹,試圖給lst賦值(因此骑疆,假設(shè)Python是在局部作用域里)。然而替废,我們正在尋找指定給lst的值是基于lst本身,其實(shí)尚未確定泊柬。
47. 修改遍歷列表
>>>odd=lambdax:bool(x%2)
>>>numbers=[nforninrange(10)]
>>>foriinrange(len(numbers)):
...ifodd(numbers[i]):
...delnumbers[i]# BAD: Deleting item from a list while iterating over it
...
Traceback(mostrecentcalllast):
File"",line2,in
IndexError:listindexoutofrange
在遍歷的時(shí)候椎镣,對(duì)列表進(jìn)行刪除操作,這是很低級(jí)的錯(cuò)誤兽赁。稍微有點(diǎn)經(jīng)驗(yàn)的人都不會(huì)犯状答。 對(duì)上面的代碼進(jìn)行修改,正確地執(zhí)行:
>>>odd=lambdax:bool(x%2)
>>>numbers=[nforninrange(10)]
>>>numbers[:]=[nforninnumbersifnotodd(n)]# ahh, the beauty of it all
>>>numbers
[0,2,4,6,8]
48. 合理使用copy與deepcopy
對(duì)于dict和list等數(shù)據(jù)結(jié)構(gòu)的對(duì)象刀崖,直接賦值使用的是引用的方式惊科。而有些情況下需要復(fù)制整個(gè)對(duì)象,這時(shí)可以使用copy包里的copy和deepcopy亮钦,這兩個(gè)函數(shù)的不同之處在于后者是遞歸復(fù)制的馆截。效率也不一樣:(以下程序在ipython中運(yùn)行)
timeit后面的-n表示運(yùn)行的次數(shù),后兩行對(duì)應(yīng)的是兩個(gè)timeit的輸出蜂莉,下同蜡娶。由此可見后者慢一個(gè)數(shù)量級(jí)。
importcopy
a=range(100000)
%timeit-n10copy.copy(a)# 運(yùn)行10次 copy.copy(a)
%timeit-n10copy.deepcopy(a)
10loops,bestof3:1.55msperloop
10loops,bestof3:151msperloop
49. 合理使用生成器(generator)和yield
%timeit-n100a=(iforiinrange(100000))
%timeit-n100b=[iforiinrange(100000)]
100loops,bestof3:1.54msperloop
100loops,bestof3:4.56msperloop
使用()得到的是一個(gè)generator對(duì)象映穗,所需要的內(nèi)存空間與列表的大小無關(guān)窖张,所以效率會(huì)高一些。在具體應(yīng)用上蚁滋,比如set(i for i in range(100000))會(huì)比set([i for i in range(100000)])快宿接。
但是對(duì)于需要循環(huán)遍歷的情況:
%timeit-n10forxin(iforiinrange(100000)):pass
%timeit-n10forxin[iforiinrange(100000)]:pass
10loops,bestof3:6.51msperloop
10loops,bestof3:5.54msperloop
后者的效率反而更高赘淮,但是如果循環(huán)里有break,用generator的好處是顯而易見的。yield也是用于創(chuàng)建generator:
50. 使用級(jí)聯(lián)比較x < y < z
x,y,z=1,2,3
%timeit-n1000000ifx
%timeit-n1000000ifx
1000000loops,bestof3:101nsperloop
1000000loops,bestof3:121nsperloop
x < y < z效率略高睦霎,而且可讀性更好梢卸。
51. while 1 比 while True 更快
defwhile_1():
n=100000
while1:
n-=1
ifn<=0:break
defwhile_true():
n=100000
whileTrue:
n-=1
ifn<=0:break
m,n=1000000,1000000
%timeit-n100while_1()
%timeit-n100while_true()
100loops,bestof3:3.69msperloop
100loops,bestof3:5.61msperloop
while 1 比 while true快很多,原因是在python2.x中碎赢,True是一個(gè)全局變量低剔,而非關(guān)鍵字。
52. 使用**而不是pow
%timeit-n10000c=pow(2,20)
%timeit-n10000c=2**20
10000loops,bestof3:284nsperloop
10000loops,bestof3:16.9nsperloop
53. 使用 cProfile, cStringIO 和 cPickle等用c實(shí)現(xiàn)相同功能(分別對(duì)應(yīng)profile, StringIO, pickle)的包
importcPickle
importpickle
a=range(10000)
%timeit-n100x=cPickle.dumps(a)
%timeit-n100x=pickle.dumps(a)
100loops,bestof3:1.58msperloop
100loops,bestof3:17msperloop
由c實(shí)現(xiàn)的包肮塞,速度快10倍以上襟齿!
54. 使用最佳的反序列化方式
下面比較了eval, cPickle, json方式三種對(duì)相應(yīng)字符串反序列化的效率,可見json比cPickle快近3倍枕赵,比eval快20多倍猜欺。
importjson
importcPickle
a=range(10000)
s1=str(a)
s2=cPickle.dumps(a)
s3=json.dumps(a)
%timeit-n100x=eval(s1)
%timeit-n100x=cPickle.loads(s2)
%timeit-n100x=json.loads(s3)
100loops,bestof3:16.8msperloop
100loops,bestof3:2.02msperloop
100loops,bestof3:798μsperloop
55. 怎么才算精通python
這個(gè)問題比較難回答,我是看怎么樣才算是精通 Python這個(gè)知乎問答拷窜,按照自己的看法整理了一些觀點(diǎn)开皿。不要問我是按什么標(biāo)準(zhǔn)整理的,我只能說篮昧,整理的這些點(diǎn)赋荆,第一,在我看來都說得不錯(cuò)懊昨;第二窄潭,我自己都會(huì)去按照這些點(diǎn)來看看自己離 “精通” python還有多遠(yuǎn)。
熟悉語法以及原聲數(shù)據(jù)結(jié)構(gòu)
熟悉基本實(shí)現(xiàn)中的性能特點(diǎn)酵颁,就是知道什么操作會(huì)慢
會(huì)使用profile以及基于profile的性能分析工具
會(huì)使用運(yùn)行時(shí)編譯和靜態(tài)編譯的工具嫉你。pypy,numba躏惋,cython幽污,ctypes,original C/C++ extension
熟悉你所在領(lǐng)域的拓展庫簿姨,比如我距误,科學(xué)計(jì)算方面的庫不要太多,numpy衍生出來的一大堆大堆
了解基本的編譯過程款熬,基本的操作系統(tǒng)知識(shí)(只要你C深寥、C++學(xué)的還行就可以了)
要想精通python,寫的代碼首先得pythonic
研讀牛B的開源代碼贤牛,在這過程中會(huì)遇到python的許多高階用法
理解裝飾器惋鹅,生成器,描述符殉簸,元類
掌握list comprehension闰集,
多用內(nèi)置函數(shù):map沽讹,reduce,filter武鲁,iter爽雄,range,divmod沐鼠,round挚瘟,chr,enumerate饲梭,all乘盖,any,slice憔涉,zip+
56. python 猴子補(bǔ)丁相關(guān)
python里有一個(gè)很奇妙的monkey patch订框,中文叫做猴子補(bǔ)丁,是指的是在運(yùn)行時(shí)動(dòng)態(tài)替換某些已加載的模塊的實(shí)現(xiàn)兜叨。第一次了解這個(gè)概念是在使用gevent的時(shí)候穿扳,需要把python自帶的socket,os等相關(guān)模塊的實(shí)現(xiàn)改變成異步形式国旷,但同時(shí)不改動(dòng)python的源代碼矛物。
57. 了解 functools.partial
先參考飄逸的python - 偏函數(shù)functools.partial
58. python 中時(shí)間格式轉(zhuǎn)換
59. python 一行代碼啟動(dòng) http 服務(wù)器
python -mSimpleHTTPServer