裝飾器的定義:
裝飾器本質上就是一個python函數,它可以讓其它函數在不需要做任何代碼改動的前提下增加額外的功能,裝飾器的返回值也是一個函數對象。它經常用於有切面需求的場景中,比如-- >插入日志、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同的代碼並且可以重復使用。
裝飾器的作用:
就是為已經存在的函數或者對象添加額外的功能
裝飾器的寫法:
(無參裝飾器)
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')時,它其實就是一個函數,會被馬上執行,只要這個它返回的結果是一個裝飾器時,那就沒有問題,再好好體會一下==
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的。
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