晚上失眠,怒上知乎答題!
剛好最近我的python專欄裡寫過一篇裝飾器相關的,不說廢話,直接上幹貨!
目錄如下:1、裝飾器是什麼?
2、如何使用裝飾器?
3、内置裝飾器
一、裝飾器是什麼?
裝飾器,顧名思義,就是增強函數或類的功能的一個函數。
這麼說可能有點繞。
舉個例子:如何計算函數的執行時間?
如下,你需要計算 add 函數的執行時間。
# 函數
def add(a, b):
res = a + b
return res
你可能會這麼寫
import time
def add(a, b)
start_time = time.time()
res = a + b
exec_time = time.time() - start_time
print("add函數,花費的時間是:{}".format(exec_time))
return res
這個時候,老闆又讓你計算減法函數(sub)的時間。不用裝飾器的話,你又得重複寫一段減法的代碼。
def sub(a, b)
start_time = time.time()
res = a - b
exec_time = time.time() - start_time
print("sub函數,花費的時間是:{}".format(exec_time))
return res
這樣顯得很麻煩,也不靈活,萬一計算時間的代碼有改動,你得每個函數都要改動。
是以,我們需要引入裝飾器。
使用裝飾器之後的代碼是這樣的
import time
# 定義裝飾器
def time_calc(func):
def wrapper(*args, **kargs):
start_time = time.time()
f = func(*args,**kargs)
exec_time = time.time() - start_time
return f
return wrapper
# 使用裝飾器
@time_calc
def add(a, b):
return a + b
@time_calc
def sub(a, b):
return a - b
是不是看起來清爽多了?
裝飾器的作用:增強函數的功能,确切的說,可以裝飾函數,也可以裝飾類。
裝飾器的原理:函數是python的一等公民,函數也是對象。
定義裝飾器
def decorator(func):
def wrapper(*args,**kargs):
# 可以自定義傳入的參數
print(func.__name__)
# 傳回傳入的方法名參數的調用
return func(*args,**kargs)
# 傳回内層函數函數名
return wrapper
二、使用裝飾器
假設decorator是定義好的裝飾器。
方法一:不用文法糖@符号
# 裝飾器不傳入參數時
f = decorator(函數名)
# 裝飾器傳入參數時
f = (decorator(參數))(函數名)
方法二:采用文法糖@符号
# 已定義的裝飾器
@decorator
def f():
pass
# 執行被裝飾過的函數
f()
裝飾器可以傳參,也可以不用傳參。
自身不傳入參數的裝飾器(采用兩層函數定義裝飾器)
def login(func):
def wrapper(*args,**kargs):
print('函數名:%s'% func.__name__)
return func(*args,**kargs)
return wrapper
@login
def f():
print('inside decorator!')
f()
# 輸出:
# >> 函數名:f
# >> 函數本身:inside decorator!
自身傳入參數的裝飾器(采用三層函數定義裝飾器)
def login(text):
def decorator(func):
def wrapper(*args,**kargs):
print('%s----%s'%(text, func.__name__))
return func(*args,**kargs)
return wrapper
return decorator
# 等價于 ==> (login(text))(f) ==> 傳回 wrapper
@login('this is a parameter of decorator')
def f():
print('2019-06-13')
# 等價于 ==> (login(text))(f)() ==> 調用 wrapper() 并傳回 f()
f()
# 輸出:
# => this is a parameter of decorator----f
# => 2019-06-13
三、内置裝飾器
常見的内置裝飾器有三種,@property、@staticmethod、@classmethod
@property
把類内方法當成屬性來使用,必須要有傳回值,相當于getter;
假如沒有定義 @func.setter 修飾方法的話,就是隻讀屬性
class Car:
def __init__(self, name, price):
self._name = name
self._price = price
@property
def car_name(self):
return self._name
# car_name可以讀寫的屬性
@car_name.setter
def car_name(self, value):
self._name = value
# car_price是隻讀屬性
@property
def car_price(self):
return str(self._price) + '萬'
benz = Car('benz', 30)
print(benz.car_name) # benz
benz.car_name = "baojun"
print(benz.car_name) # baojun
print(benz.car_price) # 30萬
@staticmethod
靜态方法,不需要表示自身對象的self和自身類的cls參數,就跟使用函數一樣。
@classmethod
類方法,不需要self參數,但第一個參數需要是表示自身類的cls參數。
例子
class Demo(object):
text = "三種方法的比較"
def instance_method(self):
print("調用執行個體方法")
@classmethod
def class_method(cls):
print("調用類方法")
print("在類方法中 通路類屬性 text: {}".format(cls.text))
print("在類方法中 調用執行個體方法 instance_method: {}".format(cls().instance_method()))
@staticmethod
def static_method():
print("調用靜态方法")
print("在靜态方法中 通路類屬性 text: {}".format(Demo.text))
print("在靜态方法中 調用執行個體方法 instance_method: {}".format(Demo().instance_method()))
if __name__ == "__main__":
# 執行個體化對象
d = Demo()
# 對象可以通路 執行個體方法、類方法、靜态方法
# 通過對象通路text屬性
print(d.text)
# 通過對象調用執行個體方法
d.instance_method()
# 通過對象調用類方法
d.class_method()
# 通過對象調用靜态方法
d.static_method()
# 類可以通路類方法、靜态方法
# 通過類通路text屬性
print(Demo.text)
# 通過類調用類方法
Demo.class_method()
# 通過類調用靜态方法
Demo.static_method()
@staticmethod 和 @classmethod 的 差別 和 使用場景:
在上述例子中,我們可以看出,
差別
在定義靜态類方法和類方法時,@staticmethod 裝飾的靜态方法裡面,想要通路類屬性或調用執行個體方法,必須需要把類名寫上;
而@classmethod裝飾的類方法裡面,會傳一個cls參數,代表本類,這樣就能夠避免手寫類名的寫死。
在調用靜态方法和類方法時,實際上寫法都差不多,一般都是通過 類名.靜态方法() 或 類名.類方法()。
也可以用執行個體化對象去調用靜态方法和類方法,但為了和執行個體方法區分,最好還是用類去調用靜态方法和類方法。
使用場景
是以,在定義類的時候,
假如不需要用到與類相關的屬性或方法時,就用靜态方法@staticmethod;
假如需要用到與類相關的屬性或方法,然後又想表明這個方法是整個類通用的,而不是對象特異的,就可以使用類方法@classmethod。
希望看到這個回答的朋友,永遠不要失眠~
另外還有一些之前在github上總結的:測試開發面試資源、複習資料彙總
最後,歡迎加入【程式員知乎交流圈】↓↓↓程式員交流圈 - 知乎www.zhihu.com
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5ybjlGcp9lZ2IWZiVmMmlDMlRzYwkjZxUWYkZmN3AjYmBzY4YzNl1iM29CXt92YucWbphmeuQzYpB3Lc9CX6MHc0RHaiojIsJye.jpg)
置頂帖我放了頭條内推連結,歡迎投遞~(北京上海深圳廣州杭州成都武漢都在招)