本篇博客為你帶來(lái) python 函數(shù)相關(guān)知識(shí)點(diǎn)的回顧菜拓。
函數(shù)是 python 語(yǔ)言中一個(gè)非常重要的概念,并且是頭等對(duì)象慎恒,可以把函數(shù)分配給變量,也可以將其作為參數(shù)傳遞給其它函數(shù)赋焕,當(dāng)然作為其它函數(shù)的返回值也是可以的耙厚。
函數(shù)就是對(duì)象
函數(shù)是對(duì)象强挫,所以可以將其賦值給一個(gè)變量
def func():
print("hello 橡皮擦")
my_var = func # 注意沒(méi)有括號(hào)
my_var() # 調(diào)用
函數(shù)是對(duì)象,所以可以出現(xiàn)在其它數(shù)據(jù)結(jié)構(gòu)中薛躬,例如列表
函數(shù)可以作為列表的項(xiàng)俯渤。
def func():
print("hello 橡皮擦")
my_list = [func, 1, 2, 3] # 列表第一項(xiàng)是函數(shù)
print(my_list)
my_list[0]() # 列表第一項(xiàng)可以調(diào)用
函數(shù)是對(duì)象,所以可以作為其它函數(shù)的參數(shù)
def func():
print("hello 橡皮擦")
def func1(func):
func() # 調(diào)用參數(shù)
func1(func) # 函數(shù)作為參數(shù)
可以接受其它函數(shù)作為參數(shù)的函數(shù)型宝,稱為高階函數(shù)八匠,這與我們之前學(xué)習(xí)的函數(shù)式編程又產(chǎn)生了關(guān)聯(lián)。
函數(shù)是對(duì)象趴酣,所以可以作為其它函數(shù)的返回值
函數(shù)作為返回值梨树,又衍生出來(lái)一個(gè)概念,函數(shù)的嵌套(內(nèi)部函數(shù))岖寞。
def func():
def inner_func():
print("內(nèi)部函數(shù)")
return inner_func
print(func()) # 輸出 <function func.<locals>.inner_func at 0x00000000028581E0>
func()() # 輸出內(nèi)部函數(shù)
如果函數(shù)作為返回值抡四,那調(diào)用外層函數(shù)只能得到一個(gè)函數(shù)對(duì)象,因此會(huì)出現(xiàn) func()()
這樣奇怪的寫法仗谆。
函數(shù)的嵌套還衍生一個(gè)概念指巡,叫做 詞法閉包,一般叫做 閉包胸私,其核心內(nèi)容是內(nèi)部函數(shù)可以訪問(wèn)父函數(shù)中的參數(shù)厌处。
def func():
f_name = "橡皮擦"
def inner_func():
print("內(nèi)部函數(shù)")
print(f_name)
return inner_func
inner = func()
inner() # 輸出內(nèi)部函數(shù)與橡皮擦
python 中小小的裝飾器
學(xué)習(xí)裝飾器的前提是掌握 函數(shù)是頭等對(duì)象。
裝飾器是用來(lái) 包裝 函數(shù)的岁疼,它可以在不修改原函數(shù)的前提下阔涉,在被包裝函數(shù)的前后增加代碼。
最簡(jiǎn)單的包裝如下捷绒,給一個(gè)函數(shù)增加運(yùn)行時(shí)間瑰排。
def func():
for i in range(100000):
pass
def time_decorator(func):
import time
start_time = time.perf_counter()
func()
print(f"{func.__name__} 運(yùn)行時(shí)間為:", time.perf_counter() - start_time)
# 裝飾 func 函數(shù)
time_decorator(func)
上述代碼中 time_decorator
就是一個(gè)裝飾器,func
函數(shù)作為參數(shù)傳遞給它暖侨,從而實(shí)現(xiàn)代碼運(yùn)行時(shí)間的獲取椭住。
使用 @函數(shù)名
可以更加方便的調(diào)用裝飾器。
def time_decorator(func):
import time
start_time = time.perf_counter()
func()
print(f"{func.__name__} 運(yùn)行時(shí)間為:", time.perf_counter() - start_time)
@time_decorator
def func():
for i in range(100000):
pass
使用 @
語(yǔ)言字逗,會(huì)立即裝飾該函數(shù)京郑,如果你想要調(diào)用 func()
,此時(shí)會(huì)出現(xiàn)如下錯(cuò)誤:
Traceback (most recent call last):
File "E:/xxxx/18.py", line 13, in <module>
func()
TypeError: 'NoneType' object is not callable
如果希望原函數(shù)還可以訪問(wèn)葫掉,需要在裝飾器函數(shù)中嵌套內(nèi)部函數(shù)些举,并將其返回。
def time_decorator(func):
import time
# 嵌套函數(shù)
def wrapper():
start_time = time.perf_counter()
func()
print(f"{func.__name__} 運(yùn)行時(shí)間為:", time.perf_counter() - start_time)
# 返回內(nèi)部函數(shù)
return wrapper
@time_decorator
def func():
for i in range(100000):
pass
func()
一個(gè)函數(shù)可以被多個(gè)裝飾器裝飾俭厚,效果從下到上運(yùn)行
從下到上理解為接近函數(shù)的裝飾器先運(yùn)行户魏。
# 加粗標(biāo)簽裝飾器
def b(func):
def wrapper():
return f'<b>{func()}</b>'
return wrapper
# 段落標(biāo)簽裝飾器
def p(func):
def wrapper():
return f'<p>{func()}</p>'
return wrapper
@p
@b
def my_func():
return "橡皮擦"
print(my_func())
裝飾器由于詞法閉包,會(huì)隱藏原函數(shù)的名稱、文檔字符串叼丑、參數(shù)列表
為了解決該問(wèn)題关翎,需要導(dǎo)入 functools
模塊中的 wraps
函數(shù),先測(cè)試一下被裝飾器修飾之后的函數(shù)相關(guān)信息鸠信。
def title(func):
def wrapper():
"""裝飾器"""
return func().title()
return wrapper
@title
def say():
return "hello world"
h = say()
print(h) # 被裝飾之后纵寝,單詞首字母大寫。
print(say.__name__) # 輸出其函數(shù)名
print(say.__doc__) # 文檔字符串
對(duì)應(yīng)的輸出內(nèi)容如下:
Hello World
wrapper
裝飾器
可以發(fā)現(xiàn) say
函數(shù)的函數(shù)名與文檔字符串都已經(jīng)被修改症副,如果不希望上述現(xiàn)象產(chǎn)生店雅,使用 functools
模塊的 wraps
函數(shù)即可。
from functools import wraps
def title(func):
@wraps(func) # 復(fù)制信息到裝飾器
def wrapper():
"""裝飾器"""
return func().title()
return wrapper
@title
def say():
"""say 函數(shù)文檔字符串"""
return "hello world"
h = say()
print(h) # 被裝飾之后贞铣,單詞首字母大寫闹啦。
print(say.__name__) # 輸出其函數(shù)名
print(say.__doc__) # 文檔字符串
對(duì)應(yīng)輸出修改為下述內(nèi)容:
Hello World
say
say 函數(shù)文檔字符串
裝飾器中的參數(shù)
在編寫裝飾器的時(shí)候,經(jīng)常碰到被裝飾的函數(shù)具有參數(shù)情況辕坝,實(shí)操過(guò)程中使用 python 變長(zhǎng)參數(shù) *
和 **
特性窍奋,即可解決該問(wèn)題。
如果函數(shù)只有一個(gè)參數(shù)酱畅,直接在 wrapper
聲明即可
def title(func):
@wraps(func) # 復(fù)制信息到裝飾器
def wrapper(name):
"""裝飾器"""
return func(name).title()
return wrapper
@title
def say(name):
"""say 函數(shù)文檔字符串"""
return name + "hello"
h = say("橡皮擦")
print(h)
*多個(gè)參數(shù)就比較繁瑣了琳袄,所以位置參數(shù)直接使用 *args,關(guān)鍵字參數(shù)使用 *kwargs
from functools import wraps
def title(func):
@wraps(func) # 復(fù)制信息到裝飾器
def wrapper(*args):
"""裝飾器"""
return func(*args).title()
return wrapper
@title
def say(name, age):
"""say 函數(shù)文檔字符串"""
return name + " hello " + " age " + str(age)
h = say("橡皮擦",18)
print(h)
下述代碼為關(guān)鍵字參數(shù)測(cè)試代碼:
from functools import wraps
def title(func):
@wraps(func) # 復(fù)制信息到裝飾器
def wrapper(*args,**kwargs):
"""裝飾器"""
return func(*args,**kwargs).title()
return wrapper
@title
def say(name):
"""say 函數(shù)文檔字符串"""
return name + " hello "
h = say(name="橡皮擦")
print(h)
總結(jié)一下:
-
*args
:用來(lái)收集額外的位置參數(shù)纺酸,組成元組窖逗; -
**kwargs
:用來(lái)收集關(guān)鍵字參數(shù),組成字典餐蔬。
其中 args
和 kwargs
非固定名稱碎紊,你可以根據(jù)需要進(jìn)行設(shè)置,不過(guò)行業(yè)里面其它程序員都遵守該規(guī)范樊诺。
寫在后面
以上內(nèi)容就是本文的全部?jī)?nèi)容仗考,希望對(duì)學(xué)習(xí)路上的你有所幫助~
更多精彩