裝飾器的定義:python
裝飾器本質上就是一個python函數,它可讓其它函數在不須要作任何代碼改動的前提下增長額外的功能,裝飾器的返回值也是一個函數對象。它常常用於有切面需求的場景中,好比-- >插入日誌、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量與函數功能自己無關的雷同的代碼而且能夠重複使用。緩存
裝飾器的做用:閉包
就是爲已經存在的函數或者對象添加額外的功能app
裝飾器的寫法:函數
(無參裝飾器) 性能
def wrapper(func): def inner(*args, **kwargs): print('in inner function') res = func(*args, **kwargs) return res return inner @wrapper def index(name): print('my name is %s' % name) index('william')
(有參裝飾器):帶參數的裝飾器和類裝飾器屬於進階的內容。在理解這些裝飾器以前,最好對函數的閉包和裝飾器的接口約定可以有必定的瞭解。測試
能夠這麼理解,當帶參數的裝飾器被打在某個函數上時,好比@outter('critical')時,它其實就是一個函數,會被立刻執行,只要這個它返回的結果是一個裝飾器時,那就沒有問題,再好好體會一下==this
def outter(level): def wrapper(func): def inner(*args, **kwargs): if level == 'info': print('in inner function') res = func(*args, **kwargs) return res else: print('level not enough') return inner return wrapper @outter('critical') def index(name): print('my name is %s' % name) index('william')
(基於類實現的裝飾器):裝飾器函數其實這樣一個接口約束,它必須接受一個__call__對象做爲參數,而後返回一個callable對象,在python中通常callable對象都是函數,可是也有例外的,只要某個對象從新加載了__call__()方法,那麼這個對象就是callable的。spa
class Wrapper: def __init__(self): self.current_name = [] def __call__(self, func): def inner(*args, **kwargs): flag = True if self.current_name: print('當前用戶已經登錄了') res = func(*args, **kwargs) return res else: while flag: user_name = input('user_name:').strip() password = input('password:').strip() if user_name == 'william' and password == '123': print('登錄成功...') res = func(*args, **kwargs) self.current_name.append(user_name) return res else: print('user_name or password error') return inner class Test: @Wrapper() def index(self, name): print('my name is %s' % name) t = Test() t.index('william')
像__call__這樣先後都帶下劃線的方法在python中被稱爲內置方法,有時候也被稱爲魔法方法,從新加載這些魔法方法通常會改變對象的內部行爲,可讓一個類對象擁有被調用的行爲。設計
class Test: def __call__(self): print('this is call') t = Test() t() # this is call
python內置的裝飾器:
@staticmethod
將類中的方法設置爲靜態方法,就是在不須要建立實例對象的狀況下,能夠經過類名來進行直接引用,來達到將函數功能與實例解綁的效果。
class Test: @staticmethod def index(x, y): print('x + y = %s' % (x+y)) cls = Test() print('能夠經過實例對象來引用') cls.index(1, 2) print('經過類名直接引用靜態方法') Test.index(1, 2) ''' 能夠經過實例對象來引用 x + y = 3 經過類名直接引用靜態方法 x + y = 3 '''
@classmethod
類方法的第一個參數是一個類,是將類的自己做爲操做的方法。類方法是被哪一個對象調用的,就傳入哪一個類做爲第一個參數進行操做。
class Car: car = 'audi' @classmethod def value(cls, category): print('%s is the %s' % (category, cls.car)) class Bmw(Car): car = 'Bmw' class Benz(Car): car = 'Benz' print('經過實例進行調用') b = Bmw() b.value('normal') print('直接用類名進行調用') Benz.value('NOnormal')
@property
使調用類中方法像引用類中的字段屬性同樣。被修飾的特性方法,內部能夠實現處理邏輯,可是對外部提供統一的調用方式,遵循了統一的訪問的原則。
class Test: name = 'test' def __init__(self, name): self.name = name @property def index(self): print('hello my name is %s' % self.name) cls = Test('file') print('經過實例來引用屬性') print(cls.name) print('像引用屬性同樣調用@property修飾的方法') cls.index