14高階函數(shù)_柯里化_裝飾器_functools_docstring

?

專業(yè)成都網(wǎng)站建設(shè)公司,做排名好的好網(wǎng)站,排在同行前面,為您帶來客戶和效益!創(chuàng)新互聯(lián)公司為您提供成都網(wǎng)站建設(shè),五站合一網(wǎng)站設(shè)計制作,服務(wù)好的網(wǎng)站設(shè)計公司,成都網(wǎng)站設(shè)計、成都網(wǎng)站制作負責任的成都網(wǎng)站制作公司!

高階函數(shù)、柯里化、裝飾器、functools、文檔字符串

?

?

目錄

高階函數(shù)...1

內(nèi)建函數(shù)-高階函數(shù)...3

currying柯里化:...4

decorator裝飾器:...4

裝飾器(無參):...7

帶參裝飾器:...9

functools:...12

文檔字符串:...14

?

?

?

高階函數(shù)

函數(shù):

first class object,函數(shù)在python中是一等公民;

函數(shù)也是對象,可調(diào)用的對象;

函數(shù)可以作為普通變量、參數(shù)、返回值等;

?

高階函數(shù)

數(shù)學(xué)概念,y=g(f(x));

在數(shù)學(xué)和計算機科學(xué)中,高階函數(shù)應(yīng)當是至少滿足下面一個條件的函數(shù):

接受一個或多個函數(shù)作為參數(shù);

輸出一個函數(shù),如return inc;

?

計數(shù)器:

例:

In [1]: def counter(base):?? #函數(shù)counter()是一個高階函數(shù)

?? ...:???? def inc(step=1):

?? ...:???????? nonlocal base

?? ...:???????? base += step?? #賦值前引用,用nonlocal解決

?? ...:???????? return base

?? ...:???? return inc

?? ...:

In [2]: foo=counter(10)

In [3]: foo1=counter(10)

In [4]: foo==foo1??#foo和foo1不一樣,可理解為inc為counter內(nèi)的標識符,每次counter()運行是不同的對象

Out[4]: False

In [5]: id(foo)

Out[5]: 139964301851096

In [6]: id(foo1)

Out[6]: 139964302182600

In [7]: foo()

Out[7]: 11

In [8]: foo()

Out[8]: 12

In [9]: foo1()

Out[9]: 11

In [10]: foo1()

Out[10]: 12

?

自定義一個sort函數(shù):

排序問題,參照內(nèi)建函數(shù)sorted,自行實現(xiàn)一個sort函數(shù)(不使用內(nèi)建函數(shù)),能夠為列表元素排序;

需求:原列表不變(sorted(lst));原列表改變(lst.sort());

思路:

內(nèi)建函數(shù)sorted返回一個新列表,可設(shè)置升序降序,可設(shè)置一個排序的函數(shù),自定義sort函數(shù)也要具備這些功能;

新建一個列表,遍歷原列表,和新列表的值依次比較決定如何插入到新列表中;

sorted函數(shù)的實現(xiàn)原理,擴展到map、filter函數(shù);

?

例:

def sort(iterable):

??? ret = []

??? for x in iterable:

??????? for i,y in enumerate(ret):

??????????? if x > y:

??????????????? ret.insert(i,x)

??????????????? break

??????? else:

??? ????????ret.append(x)

??? return ret

?

sort([5,3,2,1,4])

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

def sort(iterable,reverse=False):

??? ret = []

??? for x in iterable:

??????? for i,y in enumerate(ret):

??????????? flag = x < y if reverse else flag = x > y

??????????? if flag:

??????????????? ret.insert(i,x)?? #找到大的就插入,降序

??????????????? break

??????? else:

??????????? ret.append(x)?? #小的尾部追加

??? return ret

?

sort([5,3,2,1,4],reverse=True)

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

def sort(iterable,key=lambda a,b:a<b):?? #默認值保存在__defaults__中,只是對該匿名函數(shù)對象的引用

??? ret = []

??? for x in iterable:

??????? for i,y in enumerate(ret):

??????????? if key(x,y):

??????????????? ret.insert(i,x)

??????????????? break

??????? else:

??????????? ret.append(x)

??? return ret

?

sort([5,3,2,1,4],lambda a,b:a>b)

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

?

?

?

內(nèi)建函數(shù)-高階函數(shù)

sorted(iterable[,key][,reverse])-->new list,排序,返回一個新列表,對一個可迭代對象的所有元素排序,排序規(guī)則為key定義的函數(shù),可用reverse指定排序翻轉(zhuǎn);

例:

In [11]: lst = [3,2,4,5,1]

In [12]: sorted(lst,key=lambda x:6-x)?? #內(nèi)置sorted的key可對每個元素進行變化,該變化只在比較時用于臨時值,比較后的新列表中的元素仍然是原列表中的元素

Out[12]: [5, 4, 3, 2, 1]

In [13]: lst = ['a',1,2,3,'b']

In [15]: sorted(lst,key=str)?? #key=str為比較邏輯

Out[15]: [1, 2, 3, 'a', 'b']

?

filter(function,iterable)-->filter object,generator,過濾數(shù)據(jù),過濾可迭代的元素,返回一個迭代器;function是一個具有一個參數(shù)的函數(shù),返回bool;

例:

In [16]: filter(lambda x:x%3==0,[1,9,55,150,-3.78,28,123])

Out[16]: <filter at 0x7f4bf9d6f320>

In [17]: list(filter(lambda x:x%3==0,[1,9,55,150,-3.78,28,123]))?? #過濾出列表中能被3整除的數(shù)字;注意function中要有參數(shù)x,否則報錯

Out[17]: [9, 150, 123]

?

map(function,*iterables)-->map object,generator,映射,對多個可迭代對象的元素按指定的函數(shù)進行映射,返回一個迭代器;

例:

In [18]: map(lambda x:2*x+1,range(5))

Out[18]: <map at 0x7f4bf9d76080>

In [20]: list(map(lambda x:2*x+1,range(5)))?? #可用此方式獲取奇數(shù)、偶數(shù)

Out[20]: [1, 3, 5, 7, 9]

In [21]: dict(map(lambda x:(x%5,x),range(500)))?? #構(gòu)造字典,通過key已去重(后面覆蓋前面的了)

Out[21]: {0: 495, 1: 496, 2: 497, 3: 498, 4: 499}

?

?

?

currying柯里化:

指將原來接受2個參數(shù)的函數(shù)變成新的接受一個參數(shù)的過程,新的函數(shù)返回一個以原有第二個參數(shù)為參數(shù)的函數(shù);

z=f(x,y)-->z=f(x)(y),這種形式;

例:

將加法函數(shù)柯里化:

In [22]: def add(x,y):

??? ...:???? return x+y

??? ...:

In [23]: def add(x):

??? ...:???? def _add(y):

??? ...:???????? return x+y

??? ...:???? return _add

??? ...:

?

?

?

decorator裝飾器:

裝飾器的用途:

裝飾器是AOP思想的體現(xiàn),aspect oriented programming面向切面編程;

面向?qū)ο笸枰ㄟ^繼承或組合依賴等方式調(diào)用一些功能,這些功能的代碼往往可能在多個類中出現(xiàn),如logger,這樣造成代碼的重復(fù),增加了耦合,logger的改變影響所有使用它的類或方法;

而AOP在需要的類或方法上切下,前后的切入點可加入增強的功能,讓調(diào)用者和被調(diào)用者解耦;

這是一種不修改原來的業(yè)務(wù)代碼,給程序動態(tài)添加功能的技術(shù),如logger函數(shù)功能就是對業(yè)務(wù)函數(shù)增加日志的,而業(yè)務(wù)函數(shù)中應(yīng)把與業(yè)務(wù)無關(guān)的日志功能剝離干凈;

?

裝飾器應(yīng)用場景:

日志、監(jiān)控、權(quán)限、設(shè)計、參數(shù)檢查、路由等;

這些功能與業(yè)務(wù)功能無關(guān),很多業(yè)務(wù)都需要公共功能,所以適合獨立出來,需要的時候?qū)δ繕藢ο笤鰪姡?/p>

?

需求:

加法函數(shù),增強其功能,輸出被調(diào)用過及調(diào)用的參數(shù)信息;

例:

def add(x,y):

??? print('call: {},{}+{}'.format(add.__name__,x,y))

??? return x+y

?

add(1,2)

注:

此方式完成了需求,但有缺點;

打印語句的耦合太高,與定義的函數(shù)緊緊關(guān)聯(lián);

加法函數(shù)屬于業(yè)務(wù)功能,而輸出信息是非業(yè)務(wù)功能代碼,不該放在業(yè)務(wù)函數(shù)中,這稱為侵入式代碼;

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

def add(x,y):

??? return x+y

?

def logger(fn):

??? print('begin')

??? x=fn(4,5)

??? print('end')

??? return x

?

print(logger(add))

注:

雖做到了業(yè)務(wù)功能分離,但fn函數(shù)調(diào)用傳參是個問題;

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

del add

?

def add(x,y,*args):

??? return x+y

?

def logger(fn,x,y):

??? print('begin')

??? ret=fn(x,y)

??? print('end')

??? return ret

?

print(logger(add,4,5))

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

def add(x,y,z):

??? return x+y+z

?

def logger(fn,*args,**kwargs):?? #可變參數(shù),解決了傳參問題

??? print('begin')

??? ret=fn(*args,**kwargs)?? #參數(shù)解構(gòu)

??? print('end')

??? return ret

?

print(logger(add,4,z=5,y=6))

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

def add(x,y,z):

??? return x+y+z

?

def logger(fn):?? #在上例基礎(chǔ)上將logger柯里化

??? def _logger(*args,**kwargs):?? #可變參數(shù)

??????? print('begin')

??????? ret=fn(*args,**kwargs)?? #參數(shù)解構(gòu);閉包(fn為自由變量)

??????? print('end')

??????? return ret

??? return _logger?? #返回內(nèi)部函數(shù)的引用

?

print(logger(add)(4,5,6))

?

foo=logger(add)

print(foo(4,5,6))?? #等價于print(logger(add)(4,5,6))

?

add=logger(add)?? #等價于@logger

print(add(4,5,6))

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

def logger(fn):?? #如果此處用兩個參數(shù)def logger(fn,x),后面使用@logger時會語法錯誤,解決辦法,進一步柯里化

??? def _logger(*args,**kwargs):?? #可變參數(shù)

??????? print('begin')

??????? ret=fn(*args,**kwargs)?? #參數(shù)解構(gòu);此處閉包,正因為閉包原函數(shù)在@logger(即add=logger(add))被保留下來;此處如果寫為return ret=fn(*args,**kwargs)后面語句將不會執(zhí)行

??????? print('end')

??????? return ret?? #若無此行會破壞原函數(shù)

??? return _logger?? #外層函數(shù)應(yīng)返回內(nèi)層函數(shù)的引用

?

@logger?? #等價于add=logger(add);第一個add已指向內(nèi)層函數(shù)_logger一般起名為wrapper包裝函數(shù);第二個add(即logger(add))為原函數(shù);@logger要放到被包裝函數(shù)的上一行

def add(x,y):

??? return x+y

?

print(add(4,5))?? #此處add不是原函數(shù),而是被包裝后的內(nèi)層函數(shù)(即add=logger(add))

注:

外層函數(shù)應(yīng)返回內(nèi)層函數(shù)的引用;

外層函數(shù)的參數(shù)應(yīng)為要包裝的函數(shù),add=logger(add);

@logger即裝飾器的語法;

?

?

?

裝飾器(無參):

它是一個函數(shù);

函數(shù)作為它的形參;

返回值也是一個函數(shù);

可以使用@function方式,簡化調(diào)用;

?

裝飾器和高階函數(shù):

裝飾器是高階函數(shù),但裝飾器是對傳入函數(shù)的功能的裝飾(功能增強);

?

例:

import datetime

import time

?

def logger(fn):

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

??????? print('args={},kwargs={}'.format(args,kwargs))

??????? start = datetime.datetime.now()

??????? ret = fn(*args,**kwargs)

??????? duration = (datetime.datetime.now()) - start

??????? print('function {} took {}s'.format(fn.__name__,duration.total_seconds()))

??????? return ret

??? return wrapper

?

@logger

def add(x,y):

??? print('=========call add===========')

??? time.sleep(2)

??? return x+y

?

print(add(4,y=5))

?

例:

def copy_properties(src,dst):

??? dst.__name__ = src.__name__

??? dst.__doc__ = src.__doc__

??? dst.qualname__ = src.__qualname__

???

def logger(fn):

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

??????? '''This is a wrapper'''

??????? print('begin')

??????? ret = fn(*args,**kwargs)

??????? print('end')

??????? return ret

??? copy_properties(fn,wrapper)

??? return wrapper

?

@logger

def add(x,y):

??? '''

??? This is a additional.

???

??? return int

??? x int

??? y int

??? '''

??? ret = x + y

??? return ret

?

print(add.__name__,add.__doc__,add.__qualname__,sep='\n')

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

def copy_properties(src):

??? def wrapper(dst):

??????? dst.__name__ = src.__name__

??????? dst.__doc__ = src.__doc__

??????? dst.qualname__ = src.__qualname__

??????? return dst

??? return wrapper

???

def logger(fn):

??? @copy_properties(fn)?? #等價于wrapper=copy_properties(fn)(wrapper),出現(xiàn)的wrapper可認為都是logger內(nèi)的wrapper,copy_properties(fn)即copy_properties內(nèi)的wrapper

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

??????? '''This is a wrapper'''

??????? print('begin')

??????? ret = fn(*args,**kwargs)

??? ????print('end')

??????? return ret

??? #copy_properties(fn,wrapper)

??? return wrapper

?

@logger

def add(x,y):

??? '''

??? This is a additional.

???

??? return int

??? x int

??? y int

??? '''

??? ret = x + y

??? return ret

?

print(add.__name__,add.__doc__,add.__qualname__,sep='\n')

注:

包裝函數(shù)屬性改為被包裝函數(shù)屬性;

調(diào)用時用到的是嵌套函數(shù)內(nèi)層wrapper的屬性而不是原函數(shù)add的屬性,在使用copy_properties函數(shù)后,可讓使用者認為是原函數(shù)的屬性;

通過copy_properties函數(shù)將被包裝函數(shù)的屬性覆蓋掉包裝函數(shù);

凡是被裝飾的函數(shù)都要復(fù)制這些屬性,上例很通用;

可以將復(fù)制屬性的函數(shù)構(gòu)建成裝飾器函數(shù),帶參裝飾器;

?

?

?

帶參裝飾器:

是一個函數(shù);

函數(shù)作為它的形參;

返回值是一個不帶參的裝飾器函數(shù)(不一定);

使用@function(參數(shù)列表)方式調(diào)用;

可以看作在裝飾器外層又加了一層函數(shù);

最多也就三層;

需求:

獲取函數(shù)的執(zhí)行時長,對長超過閾值的函數(shù)記錄一下;

例:

import datetime

import time

?

def logger(t):

??? def _logger(fn):

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

??????????? '''This is a wrapper.'''

??????????? print('args={},kwargs={}'.format(args,kwargs))

??????????? start = datetime.datetime.now()

??????????? ret = fn(*args,**kwargs)

??????????? duration = (datetime.datetime.now() - start).total_seconds()

??????????? if duration > t:

????????????? ??print('function {} took {}s'.format(fn.__name__,duration))

??????????? return ret

??????? return wrapper

??? return _logger

?

@logger(3)?? #等價于add=logger(3)(add)

def add(x,y):

??? print('===============call add================')

??? time.sleep(4)

??? return x+y

?

print(add(4,5))

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

import datetime

import time

?

def copy_properties(src):

??? def wrapper(dst):

??????? dst.__name__ = src.__name__

??????? dst.__doc__ = src.__doc__

??????? dst.__qualname__ = src.__qualname__

??????? return dst

??? return wrapper

?

def logger(duration):

??? def _logger(fn):

??????? @copy_properties(fn)??#等價于add=copy_properties(add)(dst)

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

??????????? '''This is a wrapper.'''

??????????? start = datetime.datetime.now()

??????????? ret = fn(*args,**kwargs)

??????????? delta = (datetime.datetime.now() - start).total_seconds()

??????????? print('so slow') if delta > duration else print('so fast')

??????????? return ret

??????? return wrapper

??? return _logger

?

@logger(3)??#等價于add=logger(3)(add)

def add(x,y):

??? print('===============call add================')

??? time.sleep(2)

??? return x+y

?

print(add(4,5))

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

def logger(fn):?? #無論logger(add)是什么都返回10,語法允許,在裝飾器角度并沒有裝飾什么,把原函數(shù)add給廢掉了

??? return 10

?

@logger?? #add=logger(add)

def add(x,y):

??? return x+y

?

print(add)

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

import datetime

import time

?

def copy_properties(src):

??? def wrapper(dst):

??????? dst.__name__ = src.__name__

??????? dst.__doc__ = src.__doc__

??????? dst.__qualname__ = src.__qualname__

??????? return dst

??? return wrapper

?

def logger(duration,func=lambda name,duration: print('{} took {}s'.format(name,duration))):

??? def _logger(fn):

??????? @copy_properties(fn)

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

??????????? '''This is a wrapper.'''

??????????? start = datetime.datetime.now()

??????????? ret = fn(*args,**kwargs)

??????????? delta = (datetime.datetime.now() - start).total_seconds()

??????????? if delta > duration:

??????????????? func(fn.__name__,duration)

??????????? return ret

??????? return wrapper

??? return _logger

?

@logger(3)

def add(x,y):

??? print('===============call add================')

??? time.sleep(4)

??? return x+y

?

print(add(4,5))

注:

將記錄的功能提取出來,這樣就可通過外部提供的函數(shù)來靈活的控制輸出;

?

?

?

functools:

functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)

類似copy_properties功能;

wrapper包裝函數(shù),wrapped被包裝函數(shù);

元組WRAPPER_ASSIGNMENTS中是要被覆蓋的屬性,__module__模塊名,__name__名稱,__qualname__限定名,__doc__文檔,__annotations__參數(shù)注解;

元組WRAPEER_UPDATES中是要被更新的屬性,__dict__屬性字典,注意字典要用update方式;

增加一個__wrapped__屬性,保留著wrapped函數(shù);

?

例:

import datetime,time,functools

?

def logger(duration,func=lambda name,duration: print('{} took {}s'.format(name,duration))):

??? def _logger(fn):

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

??????????? '''This is a wrapper.'''

??????????? start = datetime.datetime.now()

??????????? ret = fn(*args,**kwargs)

??????????? delta = (datetime.datetime.now() - start).total_seconds()

????????? ??if delta > duration:

??????????????? func(fn.__name__,duration)

??????????? return ret

??????? functools.update_wrapper(wrapper,fn)

??? ????return wrapper

??? return _logger

?

@logger(3)

def add(x,y):

??? print('===============call add================')

??? time.sleep(4)

??? return x+y

?

print(add(4,5),add.__name__,add.__wrapped__,add.__dict__,sep='\n')

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

import datetime

import time

import functools

?

def logger(duration,func=lambda name,duration: print('{} took {}s'.format(name,duration))):

??? def _logger(fn):

??????? @functools.wraps(fn)?? #經(jīng)常用

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

??????????? '''This is a wrapper.'''

??????????? start = datetime.datetime.now()

??????????? ret = fn(*args,**kwargs)

??????????? delta = (datetime.datetime.now() - start).total_seconds()

??????????? if delta > duration:

??????????????? func(fn.__name__,duration)

??????????? return ret

??????? return wrapper

??? return _logger

?

@logger(3)

def add(x,y):

??? print('===============call add================')

??? time.sleep(4)

??? return x+y

?

print(add(4,5),add.__name__,add.__wrapped__,add.__dict__,sep='\n')

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

import functools

???

def logger(fn):

??? @functools.wraps(fn)

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

??????? '''This is a wrapper'''

??????? print('begin')

??????? ret = fn(*args,**kwargs)

??????? print('end')

??????? return ret

??? print('{} {}'.format(id(wrapper),id(fn)))

??? return wrapper

?

@logger

def add(x,y):

??? '''

??? This is a additional.

???

??? return int

??? x int

??? y int

??? '''

??? ret = x + y

??? return ret

?

print(add.__name__,add.__doc__,add.__qualname__,sep='\n')

print('*'*50)

print(id(add.__wrapped__))

print(add(4,5))

print(add.__wrapped__(4,5))?? #用包裝函數(shù)調(diào)用,如add(4,5);而不要用被包裝函數(shù)調(diào)用,如add.__wrapped__(4,5)

?

?

?

文檔字符串:

python的文檔:

在函數(shù)語句塊的第一行,且習慣是多行的文本,所以多使用三引號,約定使用雙引號;

慣例是首字母大寫,第一行寫概述,空一行,第三行寫詳細描述;

可使用特殊屬性__doc__訪問這個文檔;

?

例:

In [28]: def add(x,y):

??? ...:???? '''

??? ...:???? This is a funtion of addition.

??? ...:????

??? ...:???? return int

??? ...:???? x int

??? ...:???? y int

??? ...:???? '''

??? ...:???? return x+y

??? ...:

In [29]: print('name={}\ndoc={}'.format(add.__name__,add.__doc__))

name=add

doc=

??? This is a funtion of addition.

???

??? return int

??? x int

??? y int

???

?

In [30]: help(add)

……

?

?

分享標題:14高階函數(shù)_柯里化_裝飾器_functools_docstring
瀏覽路徑:http://bm7419.com/article2/jcshoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈靜態(tài)網(wǎng)站、用戶體驗網(wǎng)站營銷、自適應(yīng)網(wǎng)站網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司