python的裝飾器是python的特色高級(jí)功能之一,言簡意賅得說,其作用是在不改變其原有函數(shù)和類的定義的基礎(chǔ)上,給他們增添新的功能。
裝飾器存在的意義是什么呢?我們知道,在python中函數(shù)可以調(diào)用,類可以繼承,為何要必須保證不改變函數(shù)和類的定義,就使得函數(shù)有了新的功能呢?其實(shí)很好解釋。
提高代碼的簡潔程度與封裝性。如果你采用新聲明一個(gè)函數(shù),并調(diào)用原來函數(shù)的思路使得原函數(shù)功能增加了,但是一方面使用起來看著不簡潔, 另一方面當(dāng)另一個(gè)程序員使用你的代碼時(shí)再使用這樣的思路,那代碼嵌套無窮無盡,會(huì)讓代碼變得很亂,說不定改錯(cuò)了哪里,動(dòng)了原函數(shù)哪個(gè)參數(shù),就會(huì)出現(xiàn)發(fā)現(xiàn)不了的bug。
我們先來看一個(gè)簡單的例子。
def addworld(func):
def addfun():
return func() + 'world'
return addfun()
@addworld
def printhello():
return 'hello'
print(printhello)
這段代碼最后運(yùn)行出來的結(jié)果是helloworld。我們發(fā)現(xiàn),只要在原函數(shù)頭上加一個(gè)你定義好了的增添功能的模板,以后凡是加上這個(gè),都會(huì)增添一個(gè)功能,這提高了開發(fā)效率,也看著更加簡潔。
def addnum(func):
def addfun(*args, **kwargs):
ret = func(*args, **kwargs)*2
return ret
return addfun
@addnum
def printsum(a, b):
return (a+b)
i = printsum(7, 7)
print(i)
這是有參數(shù)的情況下,裝飾器的使用效果,輸出結(jié)果為28。
def addnum1(c):
def addnum(func):
def addfun(*args, **kwargs):
ret = func(*args, **kwargs)*2*c
return ret
return addfun
return addnum
@addnum1(5)
def printsum(a, b):
return (a+b)
i = printsum(7, 7)
print(i)
裝飾器本身也是可以傳參的,在這個(gè)程序中,傳入了一個(gè)常數(shù)5,最后得出的結(jié)果是140。
接下來,我們介紹幾個(gè)常用的python內(nèi)置裝飾器。
property
在綁定屬性時(shí),如果我們直接把屬性暴露出去,雖然寫起來很簡單,但是,沒辦法檢查參數(shù),導(dǎo)致可以把成績隨便改。這樣顯然是不行的,那么在函數(shù)中,我們往往如何提高程序的魯棒性呢?
class Student(object):
def get_score(self):
return self._score
def set_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
s = Student()
s.set_score(60)
value = s.get_score()
print(value)
通過調(diào)用類中的函數(shù)從而進(jìn)一步操作屬性,這樣雖然安全正確卻未免看著復(fù)雜,不貼近人類自然的屬性表現(xiàn)。
class Student(object):
@property
def score(self):
return self._score
@score.setter
def 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
s = Student()
s.score = 80
print(s.score)
而加上一個(gè)@property就可以輕松解決這個(gè)問題,是不是很奇妙?把一個(gè)getter方法變成屬性,只需要加上@property就可以了,此時(shí),@property本身又創(chuàng)建了另一個(gè)裝飾器@score.setter,負(fù)責(zé)把一個(gè)setter方法變成屬性賦值,于是,我們就擁有一個(gè)可控的屬性操作。
還可以定義只讀屬性,只定義getter方法,不定義setter方法就是一個(gè)只讀屬性。
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2014 - self._birth
上面的birth是可讀寫屬性,而age就是一個(gè)只讀屬性,因?yàn)閍ge可以根據(jù)birth和當(dāng)前時(shí)間計(jì)算出來。
我的博客即將搬運(yùn)同步至騰訊云+社區(qū),邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=3cl4ow56whog8