跟著廖雪峰老師學(xué)python (2)

若想技術(shù)精進(jìn)调榄,當(dāng)然得把基礎(chǔ)知識(shí)打得牢牢的踊赠。

廖雪峰的官方網(wǎng)站 ?python3教程,該網(wǎng)站提供的教程淺顯易懂每庆,還附帶了講學(xué)視頻筐带,非常適合初學(xué)者正規(guī)入門(mén)。

以下是通過(guò)廖雪峰python官方網(wǎng)站學(xué)習(xí)的個(gè)人查漏補(bǔ)缺缤灵。

主要內(nèi)容包括:1.切片 ?2.迭代 ?3.列表生成式 ?4.生成器 ?5.迭代器 ?6.函數(shù)式編程 ?7.map/reduce ?8.filter ?9.sorted ?10.返回函數(shù) ?11.匿名函數(shù) ?12.裝飾器 ?13.偏函數(shù)

1. 切片

切片:Python的切片非常靈活伦籍,一行代碼就可以實(shí)現(xiàn)很多行循環(huán)才能完成的操作。 ?

>>>?L = ['Michael','Sarah','Tracy','Bob','Jack'] ? ??

>>> L[0:3]

['Michael', 'Sarah', 'Tracy']

>>> L[:3]

['Michael', 'Sarah', 'Tracy']

L[0:3]表示腮出,從索引0開(kāi)始取帖鸦,直到索引3為止,但不包括索引3胚嘲。即索引0作儿,1,2馋劈,正好是3個(gè)元素立倍。如果第一個(gè)索引是0,還可以省略:L[:3]侣滩。


>>> L = list(range(100))

>>> L[-10:] ? ##取后10個(gè)

[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

>>> L[:10:2] ? ##前10個(gè)數(shù),每?jī)蓚€(gè)取一個(gè)

[0, 2, 4, 6, 8]

>>> L[::5] ? ##所有數(shù)变擒,每5個(gè)取一個(gè)

[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]

tuple也是一種list君珠,唯一區(qū)別是tuple不可變。因此娇斑,tuple也可以用切片操作策添,只是操作的結(jié)果仍是tuple材部。

字符串'xxx'也可以看成是一種list,每個(gè)元素就是一個(gè)字符唯竹。因此乐导,字符串也可以用切片操作,只是操作結(jié)果仍是字符串浸颓。


2.迭代

很多語(yǔ)言比如C語(yǔ)言物臂,迭代list是通過(guò)下標(biāo)完成的,比如Java代碼:

for (i=0; i<list.length; i++) {

? ? n=list[i];

}

Python對(duì)list列表和tuple元組迭代通過(guò) ?for ... in 來(lái)完成的产上。 ? 注:list這種數(shù)據(jù)類(lèi)型雖然有下標(biāo)棵磷,但很多其他數(shù)據(jù)類(lèi)型是沒(méi)有下標(biāo)的,但是晋涣,只要是可迭代對(duì)象仪媒,無(wú)論有無(wú)下標(biāo),都可以迭代谢鹊,比如dict就可以迭代算吩。

如何判斷一個(gè)對(duì)象是可迭代對(duì)象?方法是通過(guò)collections模塊的Iterable類(lèi)型判斷:

>>> from collections import Iterable

>>> isinstance('abc', Iterable) # str是否可迭代

True

>>> isinstance([1,2,3], Iterable) # list是否可迭代

True

>>> isinstance(123, Iterable) # 整數(shù)是否可迭代

False

判斷是不是可迭代對(duì)象方法

Python對(duì)dict字典的迭代佃扼,默認(rèn)情況下迭代的是key: ?for key in dictionary 來(lái)完成偎巢。 ?如果要迭代value,可以使用 for value in dictinary.values() 來(lái)完成松嘶。 ?如果要同時(shí)迭代key和vaule艘狭,可以使用 ?for k, v in dictionary.items() 來(lái)完成。

d={'a':1, 'b':2, 'c':3}

for key in d: ?#默認(rèn)情況下用key迭代

for value in d.values(): ?#使用value來(lái)迭代

for k, v in d.items(): ?#使用key和vaule同時(shí)迭代

如果要對(duì)list實(shí)現(xiàn)類(lèi)似Java那樣的下標(biāo)循環(huán)怎么辦翠订?Python內(nèi)置的enumerate函數(shù)可以把一個(gè)list變成索引-元素對(duì)巢音,這樣就可以在for循環(huán)中同時(shí)迭代索引和元素本身:

for循環(huán)里,同時(shí)引用了兩個(gè)變量尽超,在Python里是很常見(jiàn)的


3.列表生成式

列表生成式:列表生成式即List Comprehensions官撼,是Python內(nèi)置的非常簡(jiǎn)單卻強(qiáng)大的可以用來(lái)創(chuàng)建list的生成式。

####生成 list:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

>>>list(range(1,11))

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

####生成 list :[1x1, 2x2, 3x3, ..., 10x10]

>>>[x * x for x in range(1,11)]

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

####for循環(huán)后面還可以加上if判斷,可以篩選出僅偶數(shù)的平方

>>> [x * x for x in range(1, 11) if x % 2 == 0]

[4, 16, 36, 64, 100]

####生成全排列

>>> [m + n for m in 'ABC' for n in 'XYZ']

['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

運(yùn)用列表生成式似谁,可以寫(xiě)出非常簡(jiǎn)潔的代碼傲绣。例如,列出當(dāng)前目錄下的所有文件和目錄名巩踏,可以通過(guò)一行代碼實(shí)現(xiàn):

>>> import os # 導(dǎo)入os模塊

>>> [d for d in os.listdir('.')] ? ? # os.listdir可以列出文件和目錄

###列表生成式也可以使用兩個(gè)變量來(lái)生成list:

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }

>>> [k + '=' + v for k, v in d.items()]

['y=B', 'x=A', 'z=C']

###把一個(gè)list中所有的字符串變成小寫(xiě):

>>> L = ['Hello', 'World', 'IBM', 'Apple']

>>> [s.lower() for s in L]

['hello', 'world', 'ibm', 'apple']

運(yùn)用列表生成式秃诵,可以快速生成list,可以通過(guò)一個(gè)list推導(dǎo)出另一個(gè)list塞琼,而代碼卻十分簡(jiǎn)潔菠净。


4.生成器

為什么是生成器??毅往?——通過(guò)列表生成式牵咙,我們可以直接創(chuàng)建一個(gè)列表。但是攀唯,受到內(nèi)存限制洁桌,列表容量肯定是有限的。而且侯嘀,創(chuàng)建一個(gè)包含100萬(wàn)個(gè)元素的列表另凌,不僅占用很大的存儲(chǔ)空間,如果我們僅僅需要訪問(wèn)前面幾個(gè)元素残拐,那后面絕大多數(shù)元素占用的空間都白白浪費(fèi)了途茫。

所以,如果列表元素可以按照某種算法推算出來(lái)溪食,那我們是否可以在循環(huán)的過(guò)程中不斷推算出后續(xù)的元素呢囊卜?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間错沃。在Python中栅组,這種一邊循環(huán)一邊計(jì)算的機(jī)制,稱(chēng)為生成器:generator枢析。

要?jiǎng)?chuàng)建一個(gè)generator玉掸,有很多種方法。第一種方法很簡(jiǎn)單醒叁,只要把一個(gè)列表生成式的[ ]改成( )司浪,就創(chuàng)建了一個(gè)generator:

>>> L = [x * x for x in range(10)] ? ## [ ] 列表生成式

>>> L

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>> g = (x * x for x in range(10)) ?##( ) 生成器

>>> g

<generator object <genexpr> at 0x1022ef630>

####如果要一個(gè)一個(gè)打印出來(lái),可以通過(guò)next()函數(shù)獲得generator的下一個(gè)返回值:

>>> next(g)

0

####生成器generator也是可迭代對(duì)象把沼,使用for循環(huán)迭代

>>> g = (x * x for x in range(10))

>>> for n in g:

... ? ? print(n)

...?

我們創(chuàng)建了一個(gè)generator后啊易,基本上永遠(yuǎn)不會(huì)調(diào)用next(),而是通過(guò)for循環(huán)來(lái)迭代它饮睬,并且不需要關(guān)心StopIteration的錯(cuò)誤租谈。generator非常強(qiáng)大。如果推算的算法比較復(fù)雜捆愁,用類(lèi)似列表生成式的for循環(huán)無(wú)法實(shí)現(xiàn)的時(shí)候割去,還可以用函數(shù)來(lái)實(shí)現(xiàn)。

斐波拉契數(shù)列用列表生成式寫(xiě)不出來(lái)昼丑,但是呻逆,用函數(shù)把它打印出來(lái)卻很容易:

斐波拉契數(shù)列,函數(shù)實(shí)現(xiàn)的方式

fib函數(shù)實(shí)際上是定義了斐波拉契數(shù)列的推算規(guī)則菩帝,可以從第一個(gè)元素開(kāi)始咖城,推算出后續(xù)任意的元素憔足,這種邏輯其實(shí)非常類(lèi)似generator。也就是說(shuō)酒繁,上面的函數(shù)和generator僅一步之遙。要把fib函數(shù)變成generator控妻,只需要把print(b)改為yield b就可以了:

函數(shù)fib()和生成器fib()執(zhí)行流程不一樣

這里州袒,最難理解的就是generator和函數(shù)的執(zhí)行流程不一樣。函數(shù)是順序執(zhí)行弓候,遇到return語(yǔ)句或者最后一行函數(shù)語(yǔ)句就返回郎哭。而變成generator的函數(shù),在每次調(diào)用next()的時(shí)候執(zhí)行菇存,遇到y(tǒng)ield語(yǔ)句返回夸研,再次執(zhí)行時(shí)從上次返回的yield語(yǔ)句處繼續(xù)執(zhí)行。


5.迭代器

可以直接作用于for循環(huán)的數(shù)據(jù)類(lèi)型有以下幾種:

一類(lèi)是集合數(shù)據(jù)類(lèi)型依鸥,如list列表亥至、tuple元組、dict字典贱迟、set集合姐扮、str字符串等;

一類(lèi)是generator衣吠,包括生成器和帶yield的generator function茶敏。

這些可以直接作用于for循環(huán)的對(duì)象統(tǒng)稱(chēng)為可迭代對(duì)象Iterable

注:生成器都是Iterator對(duì)象缚俏,但list惊搏、dict、str雖然是Iterable忧换,卻不是Iterator恬惯。

把list、dict包雀、str等Iterable變成Iterator可以使用iter()函數(shù)

>>> isinstance(iter([]), Iterator)

True

>>> isinstance(iter('abc'), Iterator)

True

為什么list宿崭、dict、str等數(shù)據(jù)類(lèi)型不是Iterator迭代器對(duì)象才写?

這是因?yàn)镻ython的Iterator對(duì)象表示的是一個(gè)數(shù)據(jù)流葡兑,Iterator對(duì)象可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)數(shù)據(jù),直到?jīng)]有數(shù)據(jù)時(shí)拋出StopIteration錯(cuò)誤赞草《锏蹋可以把這個(gè)數(shù)據(jù)流看做是一個(gè)有序序列,但我們卻不能提前知道序列的長(zhǎng)度厨疙,只能不斷通過(guò)next()函數(shù)實(shí)現(xiàn)按需計(jì)算下一個(gè)數(shù)據(jù)洲守,所以Iterator的計(jì)算是惰性的,只有在需要返回下一個(gè)數(shù)據(jù)時(shí)它才會(huì)計(jì)算。Iterator甚至可以表示一個(gè)無(wú)限大的數(shù)據(jù)流梗醇,例如全體自然數(shù)知允。而使用list是永遠(yuǎn)不可能存儲(chǔ)全體自然數(shù)的。

凡是可作用于for循環(huán)的對(duì)象都是Iterable類(lèi)型叙谨;凡是可作用于next()函數(shù)的對(duì)象都是Iterator類(lèi)型温鸽,它們表示一個(gè)惰性計(jì)算的序列;集合數(shù)據(jù)類(lèi)型如list手负、dict涤垫、str等是Iterable但不是Iterator,不過(guò)可以通過(guò)iter()函數(shù)獲得一個(gè)Iterator對(duì)象竟终;Python的for循環(huán)本質(zhì)上就是通過(guò)不斷調(diào)用next()函數(shù)實(shí)現(xiàn)的蝠猬。

小結(jié)

1)切片:list、tuple统捶、str都可以切片榆芦,且切片操作非常靈活、代碼簡(jiǎn)單瘾境。

2)迭代:使用for...in xxx: 語(yǔ)句歧杏, list、tuple迷守、set犬绒、dict、str都是可迭代的兑凿。凡是可作用于for循環(huán)的對(duì)象都是Iterable類(lèi)型凯力。

3)列表生成式:使用簡(jiǎn)單語(yǔ)句生成列表[ ]

4)生成器:最簡(jiǎn)單的方法,將列表生成式[ ] 改為( ) 就是一個(gè)生成器礼华; ?將函數(shù)改為生成器函數(shù)咐鹤,使用yield,每調(diào)用一次都會(huì)在這暫時(shí)停留一下圣絮,你不再調(diào)用祈惶,我就不再走。一般使用for循環(huán)遍歷扮匠。

5)迭代器:凡是可作用于next()函數(shù)的對(duì)象都是Iterator類(lèi)型捧请,它們表示一個(gè)惰性計(jì)算的序列。




6.函數(shù)式編程

函數(shù)式編程就是一種抽象程度很高的編程范式棒搜,純粹的函數(shù)式編程語(yǔ)言編寫(xiě)的函數(shù)沒(méi)有變量疹蛉,因此,任意一個(gè)函數(shù)力麸,只要輸入是確定的可款,輸出就是確定的育韩,這種純函數(shù)我們稱(chēng)之為沒(méi)有副作用。而允許使用變量的程序設(shè)計(jì)語(yǔ)言闺鲸,由于函數(shù)內(nèi)部的變量狀態(tài)不確定筋讨,同樣的輸入,可能得到不同的輸出摸恍,因此版仔,這種函數(shù)是有副作用的。

函數(shù)式編程的一個(gè)特點(diǎn)就是误墓,允許把函數(shù)本身作為參數(shù)傳入另一個(gè)函數(shù),還允許返回一個(gè)函數(shù)益缎!

1)變量可以指向函數(shù)

>>>f=abs ?###變量f谜慌,指向函數(shù)abs

>>>f(-10)###直接調(diào)用abs()函數(shù)和調(diào)用變量f()完全相同

10

2)函數(shù)名也是變量

>>> abs = 10

>>> abs(-10) ? ?###abs已經(jīng)被更改為整數(shù),其函數(shù)功能就不能用了

Traceback (most recent call last):

????File "<stdin>", line 1, in <module>

TypeError: 'int' object is not callable

3)傳入函數(shù)

既然變量可以指向函數(shù)莺奔,函數(shù)的參數(shù)能接收變量欣范,那么一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù),這種函數(shù)就稱(chēng)之為高階函數(shù)令哟。

def add(x, y, f):

????return f(x) + f(y)

x = -5

y = 6

f = absf(x) + f(y) ==> abs(-5) + abs(6) ==> 11

把函數(shù)作為參數(shù)傳入恼琼,這樣的函數(shù)稱(chēng)為高階函數(shù),函數(shù)式編程就是指這種高度抽象的編程范式屏富。


7.map/reduce

Python內(nèi)置map()和reduce()函數(shù)晴竞。

map()高階函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù)狠半,一個(gè)是Iterable噩死,map將傳入的函數(shù)依次作用到序列的每個(gè)元素(map函數(shù)本質(zhì),函數(shù)一一作用于元素)神年,并把結(jié)果作為新的Iterator返回已维。

>>> def f(x):

... ???? return x * x

...

>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) ?#map(函數(shù)名,可迭代對(duì)象) 函數(shù)一一作用于可迭代對(duì)象中的元素已日,最后返回一個(gè)迭代器:Iterator惰性序列 ? ?r垛耳。

>>> list(r) ? ?###Iterator迭代器(惰性序列),使用list()將整個(gè)序列都計(jì)算出來(lái)飘千,并返回一個(gè)list堂鲜。

[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce()把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù)占婉,reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算(reduce函數(shù)本質(zhì)泡嘴,函數(shù)把結(jié)果再代入充當(dāng)其中的一個(gè)參數(shù)),其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

###reduce例子

>>> from functools import reduce

>>> def fn(x, y):

... ???? return x * 10 + y

...

>>> reduce(fn, [1, 3, 5, 7, 9])

13579


8.filter

Python內(nèi)置filter()函數(shù)用于過(guò)濾序列逆济。

和map()類(lèi)似酌予,filter()也接收一個(gè)函數(shù)和一個(gè)序列磺箕。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個(gè)元素抛虫,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素(filter函數(shù)本質(zhì)松靡,一一作用于元素,True/False決定是否保留)建椰。

def is_odd(n):

????return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))

# 結(jié)果: [1, 5, 9, 15]

可見(jiàn)用filter()這個(gè)高階函數(shù)雕欺,關(guān)鍵在于正確實(shí)現(xiàn)一個(gè)“篩選”函數(shù),即能夠返回True/False的函數(shù)棉姐。filter()函數(shù)返回的是一個(gè)Iterator迭代器屠列,也就是一個(gè)惰性序列,所以要強(qiáng)迫f(wàn)ilter()完成計(jì)算結(jié)果伞矩,需要用list()函數(shù)獲得所有結(jié)果并返回list笛洛。

生成素?cái)?shù):

def _odd_iter():###定義一個(gè)奇數(shù)生成器,生成無(wú)限序列

? ? n=1

? ? while True:

? ? ? ? n=n+2

? ? ? ? yield n

############################################

def _not_divisible(n):###定義一個(gè)篩選函數(shù)

? ? return lambda x: x%n>0

############################################

def primes():###定義一個(gè)生成器乃坤,不斷返回下一個(gè)素?cái)?shù)

? ? yield 2

? ? it=_odd_iter() #初始序列

? ? while True:

? ? ? ? n=next(it) #返回序列的第一個(gè)數(shù)

? ? ? ? yield n

? ? ? ? it=filter(_not_divisible(n), it) #構(gòu)造新序列

############################################

#打印100以?xún)?nèi)的素?cái)?shù):

for n in primes():

? ? if n<1000:

? ? ? ? print(n)

? ? else:

break


9.sorted

sorted()函數(shù)也是一個(gè)高階函數(shù)苛让,它還可以接收一個(gè)key函數(shù)來(lái)實(shí)現(xiàn)自定義的排序,例如按絕對(duì)值大小排序:

>>> sorted([36, 5, -12, 9, -21], key=abs)

[5, 9, -12, -21, 36]

############################################

##### 給sorted傳入key函數(shù)湿诊,即可實(shí)現(xiàn)忽略大小寫(xiě)的排序:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)

['Zoo', 'Credit', 'bob', 'about']

sorted()也是一個(gè)高階函數(shù)狱杰。用sorted()排序的關(guān)鍵在于實(shí)現(xiàn)一個(gè)映射函數(shù)。高階函數(shù)的抽象能力是非常強(qiáng)大的厅须,而且仿畸,核心代碼可以保持得非常簡(jiǎn)潔。


10.返回函數(shù)

函數(shù)作為返回值:高階函數(shù)除了可以接受函數(shù)作為參數(shù)外朗和,還可以把函數(shù)作為結(jié)果值返回颁湖。

def lazy_sum(*args):

? ? def sum():

? ? ? ? ax=0

? ? ? ? for n in args:

? ? ? ? ? ? ax=ax+n

? ????? return ax

? ? return sum ?##lazy_sum()函數(shù)的返回值為一個(gè)函數(shù)sum()

內(nèi)部函數(shù)sum()可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量,當(dāng)lazy_sum返回函數(shù)sum時(shí)例隆,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中甥捺,這種稱(chēng)為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力。再注意一點(diǎn)镀层,當(dāng)我們調(diào)用lazy_sum()時(shí)镰禾,每次調(diào)用都會(huì)返回一個(gè)新的函數(shù),即使傳入相同的參數(shù)唱逢。


11.匿名函數(shù)

當(dāng)我們?cè)趥魅牒瘮?shù)時(shí)吴侦,有些時(shí)候,不需要顯式地定義函數(shù)坞古,直接傳入匿名函數(shù)更方便备韧。

>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

[1, 4, 9, 16, 25, 36, 49, 64, 81]

關(guān)鍵字 lambda 表示匿名函數(shù), 冒號(hào)前面的 x 表示函數(shù)參數(shù)痪枫。

匿名函數(shù)有個(gè)限制织堂,就是只能有一個(gè)表達(dá)式叠艳,不用寫(xiě)return,返回值就是該表達(dá)式的結(jié)果易阳。用匿名函數(shù)有個(gè)好處附较,因?yàn)楹瘮?shù)沒(méi)有名字,不必?fù)?dān)心函數(shù)名沖突潦俺。此外拒课,匿名函數(shù)也是一個(gè)函數(shù)對(duì)象,也可以把匿名函數(shù)賦值給一個(gè)變量事示,再利用變量來(lái)調(diào)用該函數(shù)早像。Python對(duì)匿名函數(shù)的支持有限,只有一些簡(jiǎn)單的情況下可以使用匿名函數(shù)肖爵。


12.裝飾器

為什么有裝飾器扎酷??

1)由于函數(shù)也是一個(gè)對(duì)象遏匆,而且函數(shù)對(duì)象可以被賦值給變量,所以谁榜,通過(guò)變量也能調(diào)用該函數(shù)幅聘。 ? ?----能懂

eg:abs是python的內(nèi)置函數(shù), f=abs ? 則窃植,f(-11) ?等同于 abs(-11)

2)函數(shù)對(duì)象有一個(gè)__name__屬性帝蒿,可以拿到函數(shù)的名字。 ? ----能懂

eg:abs函數(shù)巷怜,通過(guò)調(diào)用這個(gè)函數(shù)的name屬性葛超,可以得到其函數(shù)名,abs.__name__ ? ? ? ?f也可以 ?f.__name__

3)假設(shè)要增強(qiáng) abs() 函數(shù)的功能延塑,比如绣张,在函數(shù)調(diào)用前后自動(dòng)打印日志,但又不希望修改 abs() 函數(shù)的定義关带,這種在代碼運(yùn)行期間動(dòng)態(tài)增加功能的方式侥涵,稱(chēng)之為“裝飾器”(Decorator)。 ? ? ? ----不是很懂

本質(zhì)上宋雏,decorator就是一個(gè)返回函數(shù)的高階函數(shù)芜飘。所以,我們要定義一個(gè)能打印日志的decorator磨总,可以定義如下:

####定義一個(gè)打印日志的迭代器####

def log(func): ? ?###接收一個(gè)函數(shù)作為輸入?yún)?shù)

? ? def wrapper(*args, **kw):###定義函數(shù)

? ? ? ? print('call %s():' %func.__name__)

? ? ? ? return func(*args, **kw) ?###返回輸入的函數(shù)

? ? return wrapper ? ####decorator裝飾器的本質(zhì)就是返回函數(shù)的高階函數(shù)嗦明,所以此裝飾器要返回函數(shù) ?wrapper

我們要借助Python的@語(yǔ)法,把decorator置于函數(shù)的定義處:

@log ?##借助@裝飾器名 ?將其置于函數(shù)定義處 ?相當(dāng)于abs=log(abs)

def abs():

### 由于log()是一個(gè)decorator蚪燕,返回一個(gè)函數(shù),所以,原來(lái)的abs()函數(shù)仍然存在设哗,只是現(xiàn)在同名的abs變量指向了新的函數(shù)屋群,于是調(diào)用abs()將執(zhí)行新函數(shù),即在log()函數(shù)中返回的wrapper()函數(shù)屁商。

然后再調(diào)用 abs() 函數(shù),不僅會(huì)運(yùn)行 abs() 函數(shù)本身,還會(huì)在運(yùn)行abs() 函數(shù)前打印一行日志营勤。

一個(gè)完整的decorator的寫(xiě)法:

import functools

def log(func):

? ? @functools.wraps(func)#重要,寫(xiě)裝飾器的時(shí)候加著壹罚,防止原函數(shù)的__name__屬性值被修改

? ? def wrapper(*args, **kw):

? ? ? ? print('call %s():' %func.__name__)

? ? ? ? return func(*args, **kw)

? ? return wrapper

帶有參數(shù)的decorator的寫(xiě)法:

import functools

def log(text):

? ? def decorator(func):

? ? ? ? @functools.wraps(func)

? ? ? ? def wrapper(*args, **kw):

? ? ? ? ? ? print('%s %s():' %(text, func.__name__))

? ? ? ? ? ? return func(*agrs, **kw)

? ? ? ? return wrapper

? ? return decorator

在面向?qū)ο螅∣OP)的設(shè)計(jì)模式中葛作,decorator被稱(chēng)為裝飾模式。OOP的裝飾模式需要通過(guò)繼承和組合來(lái)實(shí)現(xiàn)猖凛,而Python除了能支持OOP的decorator外赂蠢,直接從語(yǔ)法層次支持decorator。Python的decorator可以用函數(shù)實(shí)現(xiàn)辨泳,也可以用類(lèi)實(shí)現(xiàn)虱岂。

decorator可以增強(qiáng)函數(shù)的功能,定義起來(lái)雖然有點(diǎn)復(fù)雜菠红,但使用起來(lái)非常靈活和方便第岖。


13.偏函數(shù)

當(dāng)函數(shù)的參數(shù)個(gè)數(shù)太多,需要簡(jiǎn)化時(shí)试溯,使用functools.partial可以創(chuàng)建一個(gè)新的函數(shù)蔑滓,這個(gè)新函數(shù)可以固定住原函數(shù)的部分參數(shù),從而在調(diào)用時(shí)更簡(jiǎn)單遇绞。

int2 = functools.partial(int, base=2) ?#固定參數(shù) ? 轉(zhuǎn)換成二進(jìn)制

max2 = functools.partial(max, 10) ?# 實(shí)際上會(huì)把10作為*args的一部分自動(dòng)加到左邊

##max2(5,6,7) ?等價(jià)于 ?args=(10,5,6,7) ? max(*args)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末键袱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子摹闽,更是在濱河造成了極大的恐慌蹄咖,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件付鹿,死亡現(xiàn)場(chǎng)離奇詭異比藻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)倘屹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)银亲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人纽匙,你說(shuō)我怎么就攤上這事务蝠。” “怎么了烛缔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵馏段,是天一觀的道長(zhǎng)轩拨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)院喜,這世上最難降的妖魔是什么亡蓉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮喷舀,結(jié)果婚禮上砍濒,老公的妹妹穿的比我還像新娘。我一直安慰自己硫麻,他們只是感情好爸邢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拿愧,像睡著了一般杠河。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浇辜,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天券敌,我揣著相機(jī)與錄音,去河邊找鬼柳洋。 笑死待诅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的膳灶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼立由,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼轧钓!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起锐膜,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤毕箍,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后道盏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體而柑,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年荷逞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了媒咳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡种远,死狀恐怖涩澡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坠敷,我是刑警寧澤妙同,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布射富,位于F島的核電站,受9級(jí)特大地震影響粥帚,放射性物質(zhì)發(fā)生泄漏胰耗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一芒涡、第九天 我趴在偏房一處隱蔽的房頂上張望柴灯。 院中可真熱鬧,春花似錦拖陆、人聲如沸弛槐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乎串。三九已至,卻和暖如春速警,著一層夾襖步出監(jiān)牢的瞬間叹誉,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工闷旧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留长豁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓忙灼,卻偏偏與公主長(zhǎng)得像匠襟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子该园,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 〇酸舍、前言 本文共108張圖,流量黨請(qǐng)慎重里初! 歷時(shí)1個(gè)半月啃勉,我把自己學(xué)習(xí)Python基礎(chǔ)知識(shí)的框架詳細(xì)梳理了一遍。 ...
    Raxxie閱讀 18,952評(píng)論 17 410
  • 基礎(chǔ)1.r''表示''內(nèi)部的字符串默認(rèn)不轉(zhuǎn)義2.'''...'''表示多行內(nèi)容3. 布爾值:True双妨、False(...
    neo已經(jīng)被使用閱讀 1,673評(píng)論 0 5
  • 從來(lái)不認(rèn)為鮮花玫瑰鉆戒等物質(zhì)點(diǎn)綴的告白才是最浪漫和刻骨銘心的刁品,相反泣特,那可能都是套路,因?yàn)樽罾寺母姘资且芨惺艿綄?duì)...
    丸丸的八卦日常閱讀 367評(píng)論 0 0
  • 平平淡淡的一天下棋ing
    dq920813閱讀 103評(píng)論 0 0
  • 十四挑随、你說(shuō)的是真的嗎群扶?(下) 我要用什么樣的速度生活 才能與你再次相遇,為什么我已經(jīng)這樣努力了,可是最后的結(jié)局卻依...
    墨燔閱讀 283評(píng)論 0 2