#py函數式編程.py
#高階函數map/reduce/filter/sorted、閉包函數/返回函數、匿名函數lamber、@裝飾器decorator、偏函數functool.partial()
# =============================================================================
# #Py函數式編程.py
# #高階函數、閉包函數/返回函數、匿名函數lamber、@裝飾器decorator、偏函數functool.partial()
# #參考鏈接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017328525009056
# =============================================================================
'''
深入:
一、import functools
#functools 模塊中主要包含了一些函數裝飾器和便捷的功能函數。
1、使用:@functools.wraps(func)
通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
2、#使用:functools.partial()用來創建一個偏函數,即把一個函數的某些參數給固定住(即設置默認值),返回一個新函數。
#注意:偏函數實質上是一個 @裝飾器 的原理,即在參數列表裏追加進去 設置默認值的參數。
#如:int2('1000') 實則是運行的 int('1000',base=2)
#使用:
一、高階函數(map/reduce/filter/sorted等)
高階函數就是一個函數就可以接收另一個函數作爲參數的函數。
1、map(func,*iterables) 將參數func函數 作用於 參數*iterables裏的每一個內容,返回一個可迭代對象。
#注意 map(,)返回一個迭代器iterator,需要序列化才能輸出。
`
2、reduce(func,*iterables,initial) 將參數func函數 作用於 參數序列上,並把結果繼續和序列的下一個元素做累計計算。並最終返回值。
#注意 reduce(,) 直接返回累計作用的值。
3、filter(func,iters) 過濾序列序列。用參數func函數 過濾 參數iters序列,爲True則留下,爲False則丟棄。
#注意 filter(,)返回一個迭代器iterator,需要序列化才能輸出。
4、sorted(iterable, key=None, reverse=False) 對參數iterable序列list進行排序,
#注意 參數key可用來接收一個函數來實現自定義的排序。
#注意 參數reverse爲True則反向排序
二、返回函數(閉包)
閉包函數
#高階函數除了可以接受函數作爲參數外,還可以把函數作爲 結果值返回。
#閉包 即在 外部函數中 又定義了 內部函數,並且,內部函數 可以引用 外部函數 的參數和局部變量。
#當 外部函數 返回 內部函數 時,相關參數和變量都保存在返回的函數中,這種閉包程序結構擁有極大的威力,稱謂“閉包”。
#參考網址:https://blog.csdn.net/sc_lilei/article/details/80464645
1、使用:通過獲取主函數的魔法屬性__closure__返回的值來確定主函數是否存在閉包。
#__closure__屬性返回一個元組對象,包含了閉包引用的外部變量。
#對閉包主函數的__closure__屬性迭代後通過cell_contents來輸出閉包引用的外部變量
#如果主函數 沒有return子函數,就不存在閉包,主函數不存在_closure__屬性,返回None
#如果主函數 return的子函數不引用外部變量,也就不存在閉包,主函數的__closure__屬性同樣返回None。
2、注意:閉包函數中的return返回內容指向(return返回子函數名稱 而不是調用函數)、函數作用域。
3、注意:閉包時牢記一點:返回函數(子函數、內部函數)不要引用任何 循環變量,或者後續會發生變化的變量。
#如果子函數一定要引用循環變量,方法是再創建一個函數。
#用該函數的參數綁定循環變量當前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:
三、匿名函數lambda
#關鍵字lambda表示匿名函數,lambda x : x*x,冒號前面表示函數參數,冒號後面表達式表示函數內容
1、#使用:匿名函數可以賦值變量,lambda也是一個函數對象,也可以賦值給變量,然後通過變量來調用匿名函數。
2、#使用:匿名函數可以作爲返回值返回,如在函數定義裏最後return lambda :x*x + y*y
#注意:匿名函數作爲返回值返回,等同於return子函數,就是一個閉包函數。
3、#注意:匿名函數有個限制:只能有一個表達式,不用填寫return,返回值就是該表達式的結果
四、裝飾器@(decorator裝飾器 = 高階函數 + 閉包函數)
裝飾器本質上是接受一個函數作爲參數(高階函數行爲),並返回一個函數(閉包函數行爲)。
返回函數即子函數 中定義添加內容後 再返回主函數的參數函數。
從而實現不修改 參數函數的基礎上 在代碼運行期間動態增加功能的方式。
1、#使用:functools.wraps(func)裝飾器
#注意:裝飾器裝飾過的函數的原屬性已經改變,因爲裝飾器內部是閉包主函數return返回了子函數。
#解決辦法是 通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
2、#深入:import functools
#functools 模塊中主要包含了一些函數裝飾器和便捷的功能函數。
2.1、使用:@functools.wraps(func)
通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
五、偏函數functools.partial()
#functools 模塊中主要包含了一些函數裝飾器和便捷的功能函數。其中一個就是偏函數(Partial function)。
#偏函數可以通過設定參數的默認值,從而降低函數調用的難度。
1、#使用:functools.partial()用來創建一個偏函數,即把一個函數的某些參數給固定住(即設置默認值),返回一個新函數。
2、#注意:偏函數實質上是一個 @裝飾器 的原理,即在參數列表裏追加進去 設置默認值的參數。
#如:int2('1000') 實則是運行的 int('1000',base=2)
'''
'''
函數式編程就是一種抽象程度很高的編程範式。
函數是Python內建支持的一種封裝,我們通過把大段代碼拆成函數,通過一層一層的函數調用,就可以把複雜任務分解成簡單的任務,這種分解可以稱之爲面向過程的程序設計。
函數就是面向過程的程序設計的基本單元。
純粹的函數式編程語言編寫的函數沒有變量,因此,任意一個函數,只要輸入是確定的,輸出就是確定的,這種純函數我們稱之爲沒有副作用。
而允許使用變量的程序設計語言,由於函數內部的變量狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數是有副作用的。
函數式編程的一個特點就是,允許把函數本身作爲參數傳入另一個函數,還允許返回一個函數!
Python允許使用變量,因此,Python不是純函數式編程語言。
'''
#################### 高階函數
#高階函數
#高階函數就是一個函數就可以接收另一個函數作爲參數的函數。
#一個函數就可以接收另一個函數作爲 參數,這種函數就稱之爲高階函數。
def add(x,y,fun):
return fun(x)+fun(y)
print(add(-5,6,abs))
##########
#使用 map(func,*iterables) 將參數func函數 作用於 參數*iterables裏的每一個內容,返回一個可迭代對象。
#注意 map(,)函數返回的是一個迭代器iterato,可迭代對象,需要list獲取序列化才能輸出。
help(map)
type(map)
def f(x):
return x*x
r=map(f,[1,2,3,4,5,6,7,8,9])
print(list(r)) #注意 map(,)函數返回的是一個可迭代對象,需要list獲取序列化才能輸出。
#通過map(,)函數將int內容批量轉換成str內容
list(map(str,[1,2,3,4,5,6,7,8,9]))
##########
#使用 reduce(func,*iterables,initial) 將參數func函數 作用於 參數序列上,並把結果繼續和序列的下一個元素做累計計算。並最終返回值。
#注意 reduce(,) 直接返回累計作用的值。
#參數: func指定參數,iterables指定作用序列,initial指定初始化的序列值。
#注意:如果傳入了 initial 參數值, 那麼首先傳的就不是 iterables 的第一個和第二個元素,而是 initial值 和 iterables的第一個元素
from functools import reduce
help(reduce)
def add(x,y):
return x+y
reduce(add,[1,3,5,7,9]) #注意 reduce(,)函數返回一個累計後的值。
#####
#示例1:
#如果考慮到字符串str也是一個序列,可作爲reduce的參數2,則配合map(),就可以寫出把str轉換爲int的函數
from functools import reduce
def fn(x,y):
return x*10 + y
def char2num(s):
digits={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
return digits[s] #注意參數s需要是一個str類型 來 對應字典的鍵明key
print(reduce(fn,map(char2num,'13579'))) #將字符串'13579'作爲一個可迭代的類型參數。
#####
#示例2
#使用匿名函數lambda來簡寫示例1
from functools import reduce
DIGITS={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
def char2num(s):
return DIGITS[s]
def str2int(s):
return reduce(lambda x,y: x*10 + y, map(char2num,s))
str2int('12580')
##########
#使用 filter(func,iters) 過濾序列序列。用參數func函數 過濾 參數iters序列,爲True則留下,爲False則丟棄。
#注意 filter(,)返回一個迭代器iterator,需要序列化才能輸出。
#和map()類似,filter()也接收一個函數和一個序列。
#不同的是,filter()把傳入的函數依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素。
help(filter)
#示例在一個list中,刪掉偶數,值保留奇數:
def is_odd(n):
return n%2 == 1 #符號 %求餘,//取整。
print(list(filter(is_odd,[1,2,3,4,6,7,8,9])))
#示例把一個序列中的空字符串刪掉:
def not_empty(s):
return s and s.strip() #.strip()方法用於移除字符串頭尾指定的字符(默認移除空格或換行符,注意只能刪除開頭和結尾)
print(list(filter(not_empty,['A','','B',None,'c',' '])))
#####
#示例用fielter求素數。(素數:一個正整數,如果只有1和它本身兩個因數,則叫做素數,也叫做質數。)
#計算素數的一個方法是埃氏篩法,它的算法理解起來非常簡單:
#首先,列出從2開始的所有自然數,構造一個序列:2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取序列的第一個數2,它一定是素數,然後用2把序列的2的倍數篩掉:3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取新序列的第一個數3,它一定是素數,然後用3把序列的3的倍數篩掉:5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#取新序列的第一個數5,然後用5把序列的5的倍數篩掉:7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
#不斷篩下去,就可以得到所有的素數。
def _odd_iter():
"""先構造一個從3開始的奇數序列,
注意 這是一個生成器,並且是一個無限序列的生成器。
"""
n=1
while True:
n=n+2
yield n
def _not_divisible(n):
"""然後定義一個篩選函數"""
return lambda x: x%n > 0
def prines():
"""最後定義一個生成器,不斷返回下一個素數
這個生成器先返回第一個素數2,然後,利用filter()過濾函數不斷產生篩選後的新的序列
"""
yield 2
it=_odd_iter() #初始化序列
while True:
n=next(it)
yield n
it= filter(_not_divisible(n),it) #構造新序列
"""由於prines()也是一個無限序列,所有調用時需要設置一個退出循環的條件"""
for n in prines():
if n<1000:
print(n)
else:
break
#生成器 yield
#包含yield的語句被稱爲 生成器。
#包含 基線條件 和 遞歸條件。 即最後一個條件處理 和 循環的條件處理。
a=_odd_iter()
print(a)
next(a)
##########
#使用 sorted(iterable, key=None, reverse=False) 對參數iterable序列list進行排序,
#注意 參數key可用來接收一個函數來實現自定義的排序。
#注意 參數reverse爲True則反向排序
#示例 按絕對值大小排序
"""key參數指定的函數將作用於每一個元素上,並根據key函數返回的結果進行排序"""
sorted([36,5,-12,9,-21],key=abs)
sorted([36,5,-12,9,-21],key=abs,reverse=True)
help(sorted)
#################### 閉包函數(返回函數)
#使用 閉包函數
#高階函數除了可以接受函數作爲參數外,還可以把函數作爲 結果值返回。
#閉包 即在 外部函數中 又定義了 內部函數,並且,內部函數 可以引用 外部函數 的參數和局部變量。
#當 外部函數 返回 內部函數 時,相關參數和變量都保存在返回的函數中,這種閉包程序結構擁有極大的威力,稱謂“閉包”。
#參考網址:https://blog.csdn.net/sc_lilei/article/details/80464645
#注意:閉包函數中的return返回內容指向(return返回子函數名稱 而不是調用函數)、函數作用域。
#注意:閉包時牢記一點:返回函數(子函數、內部函數)不要引用任何循環變量,或者後續會發生變化的變量。
#如果子函數一定要引用循環變量,方法是再創建一個函數。
#用該函數的參數綁定循環變量當前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:
#使用:通過獲取主函數的魔法屬性__closure__返回的值來確定主函數是否存在閉包。
#__closure__屬性返回一個元組對象,包含了閉包引用的外部變量。
#對閉包主函數的__closure__屬性迭代後通過cell_contents來輸出閉包引用的外部變量
#如果主函數 沒有return子函數,就不存在閉包,主函數不存在_closure__屬性,返回None
#如果主函數 return的子函數不引用外部變量,也就不存在閉包,主函數的__closure__屬性同樣返回None。
#一個可變參數的求和函數
def calc_sum(*args):
"""該函數 立刻返回求和的結果ax"""
ax=0
for n in args:
ax=ax+n
return ax
#一個返回求和函數名的函數
def lazy_sum(*args):
"""該函數 返回一個函數名(不帶括號表示不運行函數),不立即求和,而是等到調用函數()時再進行求和;
閉包:
#閉包 即在 外部函數中 又定義了 內部函數,並且,內部函數 可以引用 外部函數 的參數和局部變量。
#當 外部函數 返回 內部函數 時,相關參數和變量都保存在返回的函數中,這種閉包程序結構擁有極大的威力,稱謂“閉包”。
"""
def sum():
ax=0
for n in args:
ax=ax+n
return ax
""" 閉包return返回了子函數名,不是調用子函數()"""
return sum #注意這裏是返回的 函數名,不帶括號表示不運行函數。
f=lazy_sum(1,3,5,7,9) #相當於賦值給f,賦值內容爲 主函數內return返回的子函數名
f() #這裏纔是進行了 主函數內return返回的子函數的調用,即立即求和計算結果。
#注意:閉包時牢記一點:返回函數(子函數、內部函數)不要引用任何循環變量,或者後續會發生變化的變量。
def count():
fs=[]
for i in range(1,4):
def f():
"""
#注意:閉包時牢記一點:返回函數(子函數、內部函數)不要引用任何循環變量,或者後續會發生變化的變量。
#如果子函數一定要引用循環變量,方法是再創建一個函數。
#用該函數的參數綁定循環變量當前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:
如下內容即引用了循環變量,導致實例化後輸出結果都爲9
"""
return i*i
'''for循環,追加 函數名 進 fs空列表'''
fs.append(f)
return fs
f1,f2,f3=count() #等於 f1,f2,f3=[f, f, f]
f1() #等於運行 f() 實質子函數f()裏i已經運行完畢爲最後的 3 。
f2() #等於運行 f() 實質子函數f()裏i已經運行完畢爲最後的 3 。
f3() #等於運行 f() 實質子函數f()裏i已經運行完畢爲最後的 3 。
#注意:閉包時牢記一點:返回函數(子函數、內部函數)不要引用任何循環變量,或者後續會發生變化的變量。
#如果子函數一定要引用循環變量,方法是再創建一個函數。
#用該函數的參數綁定循環變量當前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:
def count():
def f(j):
def g():
return j*j
return g
"""一個空列表fs,接下來準備append追加進如內容:內容爲 函數名帶綁定後的參數i 即 f(1)、f(2)、f(3)"""
fs=[]
for i in range(1,4):
fs.append(f(i))
return fs
f1,f2,f3=count() #這裏實質是列表多重賦值,等於 f1,f2,f3=[f(1),f(2),f(3)]
f1()
f2()
f3()
count()
#繼續加深對閉包的理解
_list = []
for i in range(3):
def func():
return i+1
func.__num__= i
""" 這裏實則添加完畢以後的 _list內容爲[func,func,func],但是每一個func的__num__不同"""
_list.append(func)
for f in _list:
print(f.__num__,
f()
)
#實際輸出
#0 3
#1 3
#2 3
#通過主函數的參數判斷 來return指定子函數。
def get_math_func(type) :
# 定義一個計算平方的局部函數
def square(n) :
return n * n
# 定義一個計算立方的局部函數
def cube(n) :
return n * n * n
# 定義一個計算階乘的局部函數
def factorial(n) :
result = 1
for index in range(2 , n + 1):
result *= index
return result
# 返回局部函數
if type == "square" :
return square
if type == "cube" :
return cube
else:
return factorial
# 調用get_math_func(),程序返回一個嵌套函數
math_func = get_math_func("cube") # 得到cube函數
print(math_func(5)) # 輸出125
math_func = get_math_func("square") # 得到square函數
print(math_func(5)) # 輸出25
math_func = get_math_func("other") # 得到factorial函數
print(math_func(5)) # 輸出120
##########
#使用:通過獲取主函數的魔法屬性__closure__返回的值來確定主函數是否存在閉包。
#__closure__屬性返回一個元組對象,包含了閉包引用的外部變量。
#對閉包主函數的__closure__屬性迭代後通過cell_contents來輸出閉包引用的外部變量
#如果主函數 沒有return子函數,就不存在閉包,主函數不存在_closure__屬性,返回None
#如果主函數 return的子函數不引用外部變量,也就不存在閉包,主函數的__closure__屬性同樣返回None。
# NO.1
def line_conf1(a, b):
def line(x):
return a * x + b
return line
# NO.2
def line_conf2():
a = 1
b = 2
def line(x):
print(a * x + b)
return line
# NO.3
def _line_(a,b):
def line_c(c):
def line(x):
return a*(x**2)+b*x+c
return line
return line_c
L=line_conf2()
print(line_conf2().__closure__) #通過獲取主函數的魔法屬性__closure__返回的值來確定主函數是否存在閉包。
for i in line_conf2().__closure__:
print(i.cell_contents) #對閉包主函數的__closure__屬性迭代後通過cell_contents來輸出閉包引用的外部變量
#####
#閉包的實際應用1
def who(name):
def do(what):
print(name,'say:',what)
return do
lucy=who('lucy')
lucy('I want drink!')
#####
#閉包的實際應用
#閉包實現快速給不同項目記錄日誌:
import logging
def log_header(logger_name):
""" """
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s [%(name)s] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
logger = logging.getLogger(logger_name)
def _logging(something,level):
""" 返回的數(子函數),通過判斷參數2 來調用日誌輸出類型,輸出內容爲參數1 """
if level == 'debug':
logger.debug(something)
elif level == 'warning':
logger.warning(something)
elif level == 'error':
logger.error(something)
else:
""" 如果沒有傳入參數2日誌級別,則手動引發異常"""
raise Exception("I dont know what you want to do?" )
return _logging
project_1_logging = log_header('project_1')
project_2_logging = log_header('project_2')
def project_1():
#多此一舉加函數
project_1_logging('this is a debug info','debug')
project_1_logging('this is a warning info','warning')
project_1_logging('this is a error info','error')
def project_2():
#多此一舉加函數
project_2_logging('this is a debug info','debug')
project_2_logging('this is a warning info','warning')
project_2_logging('this is a critical info','error')
project_1()
project_2()
#################### 匿名函數
#關鍵字lambdab表示匿名函數,lambda x : x*x,冒號前面表示函數參數,冒號後面表達式表示函數內容
#使用:匿名函數可以賦值變量,lambda也是一個函數對象,也可以賦值給變量,然後通過變量來調用匿名函數。
#使用:匿名函數可以賦值變量,lambda也是一個函數對象,也可以賦值給變量,然後通過變量來調用匿名函數。
#使用:匿名函數可以作爲返回值返回,如在函數定義裏最後return lambda :x*x + y*y
#注意:匿名函數作爲返回值返回,等同於return子函數,就是一個閉包函數。
#注意:匿名函數有個限制:只能有一個表達式,不用填寫return,返回值就是該表達式的結果
#可以使用 lambda匿名函數 結合 map高階函數 來計算乘方
list(map(lambda x: x*x,[1,2,3,4,5,6,7,8,9]))
#使用:匿名函數可以賦值變量,lambda也是一個函數對象,也可以賦值給變量,然後通過變量來調用匿名函數。
f=lambda x: x*x
f(5)
f
#使用:匿名函數作爲返回值返回,如在函數定義裏最後return lambda :x*x + y*y
#注意:匿名函數作爲返回值返回,等同於return子函數,就是一個閉包函數。
def build(x,y):
""" 匿名函數作爲返回值返回,等同於return子函數,就是一個閉包函數
注意:閉包函數注意 return的返回指向是否存在()的調用形式"""
return lambda :x*x + y*y
b=build(5,10)
b()
#可以使用lambda匿名函數 結合 map高階函數 來過濾偶數
list(filter(lambda n: n%2==1,range(1,21)))
################### 裝飾器@(decorator裝飾器 = 高階函數 + 閉包函數)
#裝飾器本質上是接受一個函數作爲參數(高階函數行爲),並返回一個函數(閉包函數行爲)。
#返回函數即子函數 中定義添加內容後 再返回主函數的參數函數。
#從而實現不修改 參數函數的基礎上 在代碼運行期間動態增加功能的方式。
#使用:functools.wraps(func)裝飾器
#注意:裝飾器裝飾過的函數的原屬性已經改變,因爲裝飾器內部是閉包主函數return返回了子函數。
#解決辦法是 通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
#深入:import functools 使用:@functools.wraps(func)
#####
#定義一個本身不需要傳入參數的裝飾器 打印日誌的裝飾器decorator
def log(func):
"""接收一個函數作爲參數,稱爲高階函數
返回子函數,稱爲閉包函數"""
def wrapper(*args,**kw):
"""返回主函數的參數函數,從而達到不修改參數函數的基礎上 動態增加print功能"""
print('開始調用函數:%s()' %func.__name__)
"""動態增加print功能後,繼續調用原函數()執行"""
return func(*args,**kw)
return wrapper
"""使用:@decorator放到 func函數定義前,相當於執行了 func=decorator(func),重新賦值定義了一個同名新函數"""
@log
def now():
print('2019/11/08')
now()
"""等同於不添加裝飾器@log情況下的如下表示:"""
#log(now)()
#now=log(now)
#now()
#####
#定義一個本身需要傳入參數的裝飾 打印日誌的裝飾器
#使用:如果裝飾器decorator本身需要傳入參數,那就需要編寫一個返回裝飾器的高階函數(即三層嵌套裝飾器函數)。
def log(who):
def decorator(func):
def wrapper(*args,**kw):
print('%s開始調用函數:%s()' %(who,func.__name__))
return func(*args,**kw)
return wrapper
return decorator
@log('小王')
def now():
print('2019/11/09')
now()
"""等同於不添加#log('小王')的如下表示:"""
#log('小張')(now)()
#now=log('小張')(now)
#now()
#####
#使用:functools.wraps(func)裝飾器
#注意:裝飾器裝飾過的函數的原屬性已經改變,因爲裝飾器內部是閉包主函數return返回了子函數。
#解決辦法是 通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
#深入:import functools
#functools 模塊中主要包含了一些函數裝飾器和便捷的功能函數。
#2.1、使用:@functools.wraps(func)
#通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func) 來糾正被此裝飾器裝飾過的func函數屬性。
import functools
def log(func):
# @functools.wraps(func)
def wrapper(*args,**kw):
print('開始調用函數:%s()' %func.__name__)
return func(*args,**kw)
return wrapper
@log
def now():
print('2019/11/09')
now()
print(now.__name__)
#對比添加了 @functools.wraps(func) 裝飾器之後的 now.__name__
import functools
def log(who):
def decorator(func):
"""使用:functools.wraps(func)裝飾器
通過給decorator裝飾器主函數內return返回的子函數 加上裝飾器functools.wraps(func)
來糾正被此裝飾器裝飾過的func函數屬性。
"""
@functools.wraps(func)
def wrapper(*args,**kw):
print('%s \n %s開始調用函數:%s' %('接下來使用了functools.wraps(func)技術',who,func.__name__))
return func(*args,**kw)
return wrapper
return decorator
@log('小劉')
def now():
print('2019/11/10')
now()
now.__name__
#################### 偏函數functools.partial()
#functools 模塊中主要包含了一些函數裝飾器和便捷的功能函數。其中一個就是偏函數(Partial function)。
#偏函數可以通過設定參數的默認值,從而降低函數調用的難度。
#使用:functools.partial()用來創建一個偏函數,即把一個函數的某些參數給固定住(即設置默認值),返回一個新函數。
#注意:偏函數實質上是一個 @裝飾器 的原理,即在參數列表裏追加進去 設置默認值的參數。
#如:int2('1000') 實則是運行的 int('1000',base=2)
#修改int()函數的默認base參數,來達到 N進制的轉換。
int('1000', base=8) #八進制:十位數上表示*8、百位數上表示64(8*8)、千位數上表示512(8*8*8)
int('10000',base=2) #二進制:十位數上表示*2、百位數上表示4(2*2)、千位數上表示8(2*2*2)
#使用:functools.partial()用來創建一個偏函數,即把一個函數的某些參數給固定住(即設置默認值),返回一個新函數。
import functools
int2=functools.partial(int,base=2)
int2('1000')
#注意:偏函數實質上是一個 @裝飾器 的原理,即在參數列表裏追加進去 設置默認值的參數。
#如:int2('1000') 實則是運行的 int('1000',base=2)
max2=functools.partial(max,10)
max2(2,5,9) #max2(2,5,9) 實則是運行的max(2,5,9,10)
py函數式編程(高階函數map/reduce/filter/sorted、閉包函數/返回函數、匿名函數lamber、@裝飾器decorator、偏函數functool.partial())
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.