Python高級編程技巧_第1頁
Python高級編程技巧_第2頁
Python高級編程技巧_第3頁
Python高級編程技巧_第4頁
Python高級編程技巧_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

Python高級編程技巧本文展示一些高級的Python設(shè)計結(jié)構(gòu)和它們的使用方法。在日常工作中,你可以根據(jù)需要選擇合適的數(shù)據(jù)結(jié)構(gòu),例如對快速查找性的要求、對數(shù)據(jù)一致性的要求或是對索引的要求等,同時也可以將各種數(shù)據(jù)結(jié)構(gòu)合適地結(jié)合在一起,從而生成具有邏輯性并易于理解的數(shù)據(jù)模型。Python的數(shù)據(jù)結(jié)構(gòu)從句法上來看非常直觀,并且提供了大量的可選操作。這篇指南嘗試將大部分常用的數(shù)據(jù)結(jié)構(gòu)知識放到一起,并且提供對其最佳用法的探討。推導式(Comprehensions)如果你已經(jīng)使用了很長時間的Python,那么你至少應該聽說過列表推導(listcomprehensions)。這是一種將for循環(huán)、if表達式以及賦值語句放到單一語句中的一種方法。換句話說,你能夠通過一個表達式對一個列表做映射或過濾操作。一個列表推導式包含以下幾個部分:一個輸入序列一個表示輸入序列成員的變量一個可選的斷言表達式一個將輸入序列中滿足斷言表達式的成員變換成輸出列表成員的輸出表達式舉個例子,我們需要從一個輸入列表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]很簡單是吧?但是這就會有4行代碼,兩層嵌套外加一個完全不必要的append操作。而如果使用filter、lambda和map函數(shù),則能夠?qū)⒋a大大簡化: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]嗯,這么一來代碼就會在水平方向上展開。那么是否能夠繼續(xù)簡化代碼呢?列表推導能夠給我們答案:num=[1,4,-5,10,-7,2,3,-1]filtered_and_squared=[x**2forxinnumifx>0]printfiltered_and_squared#[1,16,100,4,9]Python高級編程技巧迭代器(iterator)遍歷輸入序列num的每個成員x斷言式判斷每個成員是否大于零如果成員大于零,則被交給輸出表達式,平方之后成為輸出列表的成員。列表推導式被封裝在一個列表中,所以很明顯它能夠立即生成一個新列表。這里只有一個type函數(shù)調(diào)用而沒有隱式調(diào)用lambda函數(shù),列表推導式正是使用了一個常規(guī)的迭代器、一個表達式和一個if表達式來控制可選的參數(shù)。另一方面,列表推導也可能會有一些負面效應,那就是整個列表必須一次性加載于內(nèi)存之中,這對上面舉的例子而言不是問題,甚至擴大若干倍之后也都不是問題。但是總會達到極限,內(nèi)存總會被用完。針對上面的問題,生成器(Generator)能夠很好的解決。生成器表達式不會一次將整個列表加載到內(nèi)存之中,而是生成一個生成器對象(Generatorobjector),所以一次只加載一個列表元素。生成器表達式同列表推導式有著幾乎相同的語法結(jié)構(gòu),區(qū)別在于生成器表達式是被圓括號包圍,而不是方括號:num=[1,4,-5,10,-7,2,3,-1]filtered_and_squared=(x**2forxinnumifx>0)printfiltered_and_squared#<generatorobject<genexpr>at0x00583E18>foriteminfiltered_and_squared:printitem#1,16,1004,9這比列表推導效率稍微提高一些,讓我們再一次改造一下代碼:num=[1,4,-5,10,-7,2,3,-1]defsquare_generator(optional_parameter):return(x**2forxinnumifx>optional_parameter)printsquare_generator(0)#<generatorobject<genexpr>at0x004E6418>#OptionIforkinsquare_generator(0):printk#1,16,100,4,9#OptionIIg=list(square_generator(0))printg#[1,16,100,4,9]除非特殊的原因,應該經(jīng)常在代碼中使用生成器表達式。但除非是面對非常大的列表,否則是不會看出明顯區(qū)別的。下例使用zip()函數(shù)一次處理兩個或多個列表中的元素:alist=['a1','a2','a3']blist=['1','2','3']fora,binzip(alist,blist):printa,b#a11#a22#a33再來看一個通過兩階列表推導式遍歷目錄的例子:importosdeftree(top):forpath,names,fnamesinos.walk(top):forfnameinfnames:defmodify(*args,**kwargs):variable=kwargs.pop('variable',None)printvariablex,y=func(*args,**kwargs)returnx,yreturnmodify@decoratordeffunc(a,b):printa**2,b**2returna**2,b**2func(a=4,b=5,variable="hi")func(a=4,b=5)#hi#1625#None#1625上下文管理庫(ContextLib)contextlib模塊包含了與上下文管理器和with聲明相關(guān)的工具。通常如果你想寫一個上下文管理器,則你需要定義一個類包含__enter__方法以及__exit__方法,例如:importtimeclassdemo:def__init__(self,label):self.label=labeldef__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))完整的例子在此:importtimeclassdemo:def__init__(self,label):self.label=labeldef__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=10000000whilen>0:n-=1#counting:1.36000013351上下文管理器被with聲明所激活,這個API涉及到兩個方法。1.__enter__方法,當執(zhí)行流進入with代碼塊時,__enter__方法將執(zhí)行。并且它將返回一個可供上下文使用的對象。2.當執(zhí)行流離開with代碼塊時,__exit__方法被調(diào)用,它將清理被使用的資源。利用@contextmanager裝飾器改寫上面那個例子:fromcontextlibimportcontextmanagerimporttime@contextmanagerdefdemo(label):start=time.time()try:yieldfinally:end=time.time()print('{}:{}'.format(label,end-start))withdemo('counting'):n=10000000whilen>0:n-=1#counting:1.32399988174看上面這個例子,函數(shù)中yield之前的所有代碼都類似于上下文管理器中__enter__方法的內(nèi)容。而yield之后的所有代碼都如__exit__方法的內(nèi)容。如果執(zhí)行過程中發(fā)生了異常,則會在yield語句觸發(fā)。描述器(Descriptors)描述器決定了對象屬性是如何被訪問的。描述器的作用是定制當你想引用一個屬性時所發(fā)生的操作。構(gòu)建描述器的方法是至少定義以下三個方法中的一個。需要注意,下文中的instance是包含被訪問屬性的對象實例,而owner則是被描述器修辭的類。__get__(self,instance,owner)–這個方法是當屬性被通過(value=obj.attr)的方式獲取時調(diào)用,這個方法的返回值將被賦給請求此屬性值的代碼部分。__set__(self,instance,value)–這個方法是當希望設(shè)置屬性的值(obj.attr=‘value’)時被調(diào)用,該方法不會返回任何值。__delete__(self,instance)–當從一個對象中刪除一個屬性時(delobj.attr),調(diào)用此方法。譯者注:對于instance和owner的理解,考慮以下代碼:classCelsius(object):def__init__(self,value=0.0):self.value=float(value)def__get__(self,instance,owner):returnself.valuedef__set__(self,instance,value):self.value=float(value)classTemperature(object):celsius=Celsius()temp=Temperature()temp.celsius#callsCelsius.__get__上例中,instance指的是temp,而owner則是Temperature。LazyLoadingProperties例子:importweakrefclasslazyattribute(object):def__init__(self,f):self.data=weakref.WeakKeyDictionary()self.f=fdef__get__(self,obj,cls):ifobjnotinself.data:self.data[obj]=self.f(obj)returnself.data[obj]classFoo(object):@lazyattributedefbar(self):print"Beinglazy"return42f=Foo()printf.bar#Beinglazy#42printf.bar#42描述器很好的總結(jié)了Python中的綁定方法(boundmethod)這個概念,綁定方法是經(jīng)典類(classicclasses)的實現(xiàn)核心。在經(jīng)典類中,當在一個對象實例的字典中沒有找到某個屬性時,會繼續(xù)到類的字典中查找,然后再到基類的字典中,就這么一直遞歸的查找下去。如果在類字典中找到這個屬性,解釋器會檢查找到的對象是不是一個Python函數(shù)對象。如果是,則返回的并不是這個對象本身,而是返回一個柯里化(curryingfunction)的包裝器對象。當調(diào)用這個包裝器時,它會首先在參數(shù)列表之前插入實例,然后再調(diào)用原函數(shù)。譯者注:1.柯里化–/wiki/%E6%9F%AF%E9%87%8C%E5%8C%962.function,method,boundmethod及unboundmethod的區(qū)別。首先,函數(shù)(function)是由def或lambda創(chuàng)建的。當一個函數(shù)在class語句塊中定義或是由type來創(chuàng)建時,它會轉(zhuǎn)成一個非綁定方法(unboundmethod),而當通過類實例(instance)來訪問此方法的時候,它將轉(zhuǎn)成綁定方法(boundmethod),綁定方法會自動將實例作為第一個參數(shù)傳入方法。綜上所述,方法是出現(xiàn)在類中的函數(shù),綁定方法是一個綁定了具體實例的方法,反之則是非綁定方法。綜上,描述器被賦值給類,而這些特殊的方法就在屬性被訪問的時候根據(jù)具體的訪問類型自動地調(diào)用。元類(MetaClasses)元類提供了一個改變Python類行為的有效方式。元類的定義是“一個類的類”。任何實例是它自己的類都是元類。classdemo(object):passobj=demo()print"Classofobjis{0}".format(obj.__class__)print"Classofobjis{0}".format(demo.__class__)#Classofobjis<class'__main__.demo'>#Classofobjis<type'type'>在上例中,我們定義了一個類demo,并且生成了一個該類的對象obj。首先,可以看到obj的__class__是demo。有意思的來了,那么demo的class又是什么呢?可以看到demo的__class__是type。所以說type是python類的類,換句話說,上例中的obj是一個demo的對象,而demo本身又是type的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論