連載|想用Python作自動化測試?完全學會裝飾器

 用好裝飾器,纔是真正的Python工程師。
html


14.1 概念

所謂的裝飾器,其實就是經過裝飾器函數,來修改原函數的一些功能,使得原函數不須要修改。裝飾器依賴前面介紹的Python函數的五個特性:python

  • 函數也是對象ruby

  • 函數對象能夠賦值給變量微信

  • 函數對象能夠做爲參數傳遞給另外的函數app

  • 函數對象能夠做爲另一個函數的返回值編輯器

  • 函數能夠嵌套定義ide

14.2 函數裝飾器

14.2.1 裝飾器的簡單例子

my_decorator() 是一個裝飾器,它把真正須要執行的函數 func() 包裹在其中,而且改變了它的行爲,可是原函數 func不變。定義裝飾器分三步走:函數

  • 調用原函數先後作一通操做post

  • 調用原函數學習

  • 返回內部函數對象

def my_decorator(func):  def wrapper(): print('wrapper of decorator') # ①這裏作一通操做 func() # ②調用原函數 return wrapper # ③返回內部函數對象
def greet(): print('hello world')
greet = my_decorator(greet) # 變量 greet 指向了內部函數 wrapper()greet() # 調用 greet() 至關於執行內部函數wrapper
@my_decorator # @語法糖,至關於greet1 = my_decorator(greet1)def greet1(): print('hello world')

14.2.2 裝飾帶有參數的函數

裝飾器能夠接受原函數任意類型和數量的參數,把*args和**kwargs,做爲裝飾器內部函數 wrapper() 的參數便可。

def my_decorator(func): # 這個func只是個參數,不必定是函數名。 def wrapper(*args, **kwargs):  print('wrapper of decorator') # 這裏作一通操做 func(*args, **kwargs) # 調用原函數 return wrapper # 返回內部函數對象
@my_decoratordef greet(message): print(message)
@my_decoratordef celebrate(name, message): print(name+message)

14.2.3 裝飾器自己帶有參數

它還能夠接受本身定義的參數。舉個例子,好比我想要定義一個參數,來表示裝飾器內部函數被執行的次數,那麼就能夠寫成下面這種形式:在外邊再套一層函數,並返回內層函數。參考:

def repeat(num): def my_decorator(func): def wrapper(*args, **kwargs): for i in range(num): print('wrapper of decorator') func(*args, **kwargs) return wrapper return my_decorator
@repeat(4)def greet(message): print(message)

再看一個裝飾器自己帶參數的例子:

def type_decorator(**kwargs): """檢查實例屬性類型的裝飾器""" def decorate(cls): # 對instance進行裝飾 for key, value in kwargs.items(): # 給cls的設置類屬性,並給類屬性設置描述符實例 setattr(cls, key, TypedAssertion(key, value)) return cls
return decorate

TypedAssertion是一個描述符。這個裝飾器的目標是給cls類添加kwargs中的key做爲類屬性,將TypedAssertion描述符做爲類屬性的值。舉個例子:

@type_decorator(brand=str, shares=int, price=float)class Stock: def __init__(self, brand, shares, price): self.brand = brand self.shares = shares self.price = price

效果就是對brand、shares和price屬性作了類型校驗。

14.2.4 保留被裝飾函數的元信息

在內部函數上面用裝飾器@functools.wraps(func)。

import functools
def my_decorator(func): @functools.wraps(func) # 爲了保留被裝飾函數的元信息 def wrapper(*args, **kwargs): print('wrapper of decorator') func(*args, **kwargs) return wrapper @my_decoratordef greet(message): print(message)

14.3 類裝飾器

這部分能夠看完後面關於Python類的章節後再學習。類裝飾器主要依賴於函數__call__,每當你調用一個類的實例時,__call__就會被執行。

這裏,咱們定義了類 Count,初始化時傳入原函數 func(),而__call__函數表示讓變量 num_calls 自增 1,而後打印,而且調用原函數,並返回原函數。

所以,在咱們第一次調用函數 example() 時,num_calls 的值是 1,而在第二次調用時,它的值變成了 2。

class Count: def __init__(self, func): self.func = func self.num_calls = 0
def __call__(self, *args, **kwargs): self.num_calls += 1 # 調用次數加1 print('num of calls is: {}'.format(self.num_calls)) return self.func(*args, **kwargs)
@Count # Count類裝飾example,會調用Count類的__call__函數def example(): print("hello world")
example()
# 輸出num of calls is: 1hello world
example()
# 輸出num of calls is: 2hello world

14.4 裝飾器的嵌套使用

函數能夠被多個裝飾器裝飾,也就是下面這樣:

@decorator1@decorator2@decorator3def func(): ...

裝飾器的執行順序是從裏到外,等效於decorator1(decorator2(decorator3(func)))。

14.5 實際應用場景

  • 1.身份認證

    每次調用這個函數前,都會先檢查用戶是否處於登陸狀態,若是是登陸狀態,則容許這項操做;若是沒有登陸,則不容許。

import functools
def authenticate(func): @functools.wraps(func) def wrapper(*args, **kwargs): request = args[0] if check_user_logged_in(request): # 若是用戶處於登陸狀態 return func(*args, **kwargs) # 執行函數post_comment() else: raise Exception('Authentication failed') return wrapper @authenticatedef post_comment(request, ...) ...
  • 2.測試某些函數的執行時間

import timeimport functools
def log_execution_time(func): @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() res = func(*args, **kwargs) end = time.perf_counter() print('{} took {} ms'.format(func.__name__, (end - start) * 1000)) return res return wrapper @log_execution_timedef calculate_similarity(items): ...
  • 3.輸入合理性檢查

import functools
def validation_check(input): @functools.wraps(func) def wrapper(*args, **kwargs): ... # 檢查輸入是否合法 @validation_checkdef neural_network_training(param1, param2, ...): ...

參考資料:

https://foofish.net/python-decorator.html  

https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p11_write_decorators_that_add_arguments_to_functions.html


本文分享自微信公衆號 - 明說軟件測試(liuchunmingnet)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索