裝飾器本質上是一個Python函數,它可讓其餘函數在不須要作任何代碼變更的前提下增長額外功能,裝飾器的返回值也是一個函數對象。它常常用於有切面需求的場景,好比:插入日誌、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量與函數功能自己無關的雷同代碼並繼續重用。緩存
簡單的設計了一個驗證權限的裝飾器,設計以下app
# -*- coding:utf-8 -*- def check_is_admin(func): def wrapper(*args,**kwargs): if kwargs.get('username') != 'admin': raise Exception('This user is not allowed to get food') return func(*args,**kwargs) return wrapper class Store(object): @check_is_admin def get_food(self,username,food): return self.get(food) @check_is_admin def put_food(self, username, food): return self.put(food) def get(self,food): return food def put(self,food): return food if __name__ == '__main__': s = Store() s.get_food(**{'username':'admin1'},**{'food':'apple'})
到目前爲止,咱們的示例中老是假設裝飾器有一個名爲username的關鍵字參數傳入,可是實際狀況並不是如此,因此咱們設計了一個更智能的裝飾器,代碼以下:函數
# -*- coding:utf-8 -*- import functools,inspect def check_is_admin(func): @functools.wraps(func) def wrapper(*args,**kwargs): func_args = inspect.getcallargs(func,*args,**kwargs) if func_args.get('username') != 'admin': raise Exception('This user is not allowed to get food') return func(*args,**kwargs) return wrapper class Store(object): @check_is_admin def get_food(self,username,food): return self.get(food) @check_is_admin def put_food(self, username, food): return self.put(food) def get(self,food): return food def put(self,food): return food if __name__ == '__main__': s = Store() food = s.get_food(**{'username': 'admin'}, food='apple') print(food)
這裏咱們引入了functools,inspect模塊。inspect.getcallargs承擔了主要工做,它返回一個將參數名字和值做爲鍵值對的字典{'username':'admin','food':'apple'},這就意味着裝飾器沒必要檢查參數username是基於位置的參數仍是基於關鍵字的參數,而是隻須要在字典中查詢。性能