【python 8】python 装饰器
文章目錄
- 一、什么是 python 裝飾器
- 二、裝飾器的使用
- 三、裝飾器類型
- 3.1 特性裝飾器 @property
- 3.2 類裝飾器 @classmethod
- 3.3 靜態裝飾器 @staticmethod
- 3.4 抽象方法裝飾器 @abstractmethod
一、什么是 python 裝飾器
裝飾器是一個 python 的函數,可以讓其他函數在不增加任何代碼的情況下增加功能,也就是將其他函數“包裝”起來,可以簡化代碼,做到代碼重用。
裝飾器能接收一個函數作為輸入,返回值也是一個函數對象。
二、裝飾器的使用
例子來源
def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunctiondef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration() #outputs: "I am the function which needs some decoration to remove my foul smell"a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) #now a_function_requiring_decoration is wrapped by wrapTheFunction()a_function_requiring_decoration() #outputs:I am doing some boring work before executing a_func() # I am the function which needs some decoration to remove my foul smell # I am doing some boring work after executing a_func()從上面這個例子可以看出,裝飾器就是能把扔進他的函數做一個裝飾。@符號是裝飾器的語法糖,使用@符號的寫法如下:
@a_new_decorator def a_function_requiring_decoration():"""Hey you! Decorate me!"""print("I am the function which needs some decoration to ""remove my foul smell")a_function_requiring_decoration() #outputs: I am doing some boring work before executing a_func() # I am the function which needs some decoration to remove my foul smell # I am doing some boring work after executing a_func()#the @a_new_decorator is just a short way of saying: a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)我們都知道函數有一些原信息,如 docstring, _ _name _ _等,如果使用裝飾器的話,原函數的元信息就會被裝飾器的信息所代替,如下所示:
print(a_function_requiring_decoration.__name__) # Output: wrapTheFunction所以 python 提供了一個裝飾器:functools.wraps,wraps 本身就是一個裝飾器,能把原函數的元信息拷貝到裝飾器函數中,使得裝飾器函數有和原函數一樣的元信息。
from functools import wrapsdef a_new_decorator(a_func):@wraps(a_func)def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunction@a_new_decorator def a_function_requiring_decoration():"""Hey yo! Decorate me!"""print("I am the function which needs some decoration to ""remove my foul smell")print(a_function_requiring_decoration.__name__) # Output: a_function_requiring_decoration所以,典型的藍本如下:
from functools import wraps def decorator_name(f):@wraps(f)def decorated(*args, **kwargs):if not can_run:return "Function will not run"return f(*args, **kwargs)return decorated@decorator_name def func():return("Function is running")can_run = True print(func()) # Output: Function is runningcan_run = False print(func()) # Output: Function will not run三、裝飾器類型
常見的內置裝飾器有三種:
- @property
- @staticmethod
- @classmethod
3.1 特性裝飾器 @property
@property: 可以把一個方法變成其同名屬性,以支持實例訪問和調用
在函數前面加上 @property 后,就可以把 getter 和 setter 方法變成屬性,定義 getter 方法就是一個只讀屬性,定義 setter 方法就是一個可讀可寫的。
class Student(object):@propertydef score(self):return self._score@score.setterdef score(self, value):if not isinstance(value, int):raise ValueError('score must be an integer!')if value < 0 or value > 100:raise ValueError('score must between 0 ~ 100!')self._score = value # birth 是可讀寫屬性,age 是只讀屬性,注意這里 birth 函數返回的是 self._birth,不能返回 self.birth class Student(object):@propertydef birth(self):return self._birth@birth.setterdef birth(self, value):self._birth = value@propertydef age(self):return 2015 - self._birth3.2 類裝飾器 @classmethod
@classmethod : 用來指定一個類的方法為類方法,其修飾的方法不需要實例化,不需要 self 參數,但第一個參數需要是表示自身類的 cls 參數,可以來調用類的屬性,類的方法,實例化對象等
傳入的 cls 通常用作類方法的第一參數,對于普通的類來說,要使用的話必須先進行實例化,而在一個類中,某個函數前面加上了 classmethod 或 staticmethod,這個函數就可以不用實例化,可以直接通過類名進行調用。
class A:@classmethoddef func(cls, arg1, arg2):...例子:
import time class Date:def __init__(self, year, month, day):self.year = yearself.month = monthself.day = day@classmethoddef today(cls):t = time.localtime()return cls(t.tm_year, t.tm_mon, t.tm_mday)調用:
a = Date(2020, 4, 6) b = Date.today()3.3 靜態裝飾器 @staticmethod
改變一個方法為靜態方法,靜態方法不需要傳遞隱性的第一參數,靜態方法的本質類型就是一個函數。
靜態方法可以直接通過類進行調用,也可以通過實例進行調用:
import time class Date:def __init__(self,year,month,day):self.year=yearself.month=monthself.day=day@staticmethoddef now(): #用Date.now()的形式去產生實例,該實例用的是當前時間t=time.localtime() #獲取結構化的時間格式return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建實例并且返回@staticmethoddef tomorrow():#用Date.tomorrow()的形式去產生實例,該實例用的是明天的時間t=time.localtime(time.time()+86400)return Date(t.tm_year,t.tm_mon,t.tm_mday) a = Data(2020, 4, 6) print(a.year, a.month, a.day) # 靜態方法無需實例化 b = Data.now() print(b.year, b.month, b.day) c = Data.tomorrow print(c.year, c.month, c.day) # 靜態方法也可實例化后調用 a.now()3.4 抽象方法裝飾器 @abstractmethod
抽象方法表示基類的中一個方法,在基類中沒有實現,所以不能被實例化,在子類中實現了以后才能被實例化,繼承了含有抽象方法基類類的子類必須復寫所有的抽象方法,未被 @abstractmethod 修飾的可以不重寫。
abstractmethod 的好處在哪里:
可以把某個方法裝飾成抽象的方法,類似于接口,可以用具有同一屬性的對象實現同一個抽象的方法,這樣無論是維護還是從代碼結構來說,都比較清晰。
from abc import ABC, abstractmethod class a(ABC):@abstractmethoddef writeblog(self):pass class b(a):def writeblog(self):print('writing blogs')if __name__=='__main__':# 使用如下的方法會報錯,因為被抽象裝飾器裝飾的方法需要不能直接實例化c = a()# 可以讓 b 繼承 a,然后在 b 里邊重寫被裝飾的 writeblog 的方法,然后實例化 bc = b()c.writeblog() # output 'writing blogs'總結
以上是生活随笔為你收集整理的【python 8】python 装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【语义分割】ICCV21_Self-Re
- 下一篇: 【python 9】python注册器