[TOC]
## 裝飾器(Decorators)
裝飾器,是**修改其他函數的功能的函數**。
`在原實現函數不修改的基礎上,對原函數功能進行擴展。最終提供的調用方式保持一致。`
### 無參裝飾器
假設現在線上有個函數`get_data`
```python
def get_data():
print("I am getting data...")
# 調用方式
get_data()
```
運行結果是:
```cmd
I am getting data...
```
現在領導要求,下個版本開始,`get_data`需要先進行登錄驗證,獲取到數據后,還要需要記錄用戶的操作日志。
在python中,有個神奇的功能,可以在不修改原函數的前提下,擴展修改原函數的功能。如下:
```python
def wrapper(main_func):
def inner():
print("login function called here.")
main_func()
print("log function called here.")
return inner
def get_data():
print("I am getting data...")
# 調用方式
get_data = wrapper(get_data)
get_data()
```
運行結果是:
```cmd
login function called here.
I am getting data...
log function called here.
```
通過運行結果,已經實現了在獲取數據前先進行了登錄,獲取數據后,又進行的日志打印。
再看一下修改情況,發現原來的`get_data`函數并沒有修改,只是額外添加了一個`wrapper`函數。
**分析`wrapper`函數:**
1. wrapper函數接收一個函數對象`main_func`作為入參
2. wrapper函數在內部定義了一個內部函數`inner`
*(在inner函數中,先處理了登錄,然后調用了傳入的`main_func`函數,最后處理日志打印)。*
3. 然后wrapper函數返回一個內部函數`inner`。
在調用`get_data` 的方式上,做了如下修改
```python
get_data = wrapper(get_data)
get_data()
```
先將get_data函數傳遞到wrapper函數中,獲得內部函數inner,然后將inner賦值會給`get_data`,如此一來,執行`get_data()`,便等同于執行`inner()`
在python中,有種語法,叫**裝飾器**,上面示例中,`wrapper`便可稱為“裝飾器”。我們可以用更加優雅的方式來調用裝飾器,并且無需修改調用方式。
```python
def wrapper(main_func):
def inner():
print("login function called here.")
main_func()
print("log function called here.")
return inner
@wrapper
def get_data():
print("I am getting data...")
# 調用方式
get_data()
```
調用方式無需調整,原函數`get_data`無需調整,只需添加一個裝飾器`wrapper`,然后再原函數`get_data`定義前,添加需要使用的裝飾器 **`@wrapper`** 即可。
### 帶參裝飾器
上面的例子,被修飾的函數沒有帶參數,裝飾器本身也沒有帶參數。下面修改一下,讓它們都可以帶上參數。
```python
def wrapper(user, pwd):
def outer(main_func):
def inner(*args, **kwargs):
print("login function called here.user=[%s],password=[%s]" % (user, pwd))
main_func(*args, **kwargs)
print("log function called here.")
return inner
return outer
@wrapper("gfc@126.com", "123456")
def get_data(*args, **kwargs):
print("I am getting data...")
print(args)
print(kwargs)
# 調用方式
get_data("Milton", age=18)
```
運行結果如:
```cmd
login function called here.user=[gfc@126.com],password=[123456]
I am getting data...
('Milton',)
{'age': 18}
log function called here.
```
分析代碼執行流程如下:
**執行`get_data("Milton",age=18)`時:**
1. 先執行`wrapper("gfc@126.com","123456")`, 返回outer函數
```python
def outer(main_func):
def inner(*args, **kwargs):
print("login function called here.user=[%s],password=[%s]" % ("gfc@126.com", "123456"))
main_func(*args, **kwargs)
print("log function called here.")
return inner
```
2. 執行`outer(get_data)`,返回inner函數
```python
def inner(*args, **kwargs):
print("login function called here.user=[%s],password=[%s]" % ("gfc@126.com", "123456"))
get_data(*args, **kwargs)
print("log function called here.")
```
3. 執行`inner("Milton",age=18)`
```python
print("login function called here.user=[%s],password=[%s]" % ("gfc@126.com", "123456"))
get_data("Milton",age=18)
print("log function called here.")
```
<hr style="margin-top:100px">
:-: 
***微信掃一掃,關注“python測試開發圈”,了解更多測試教程!***
- 前言
- chapter01_開發環境
- chapter02_字符串的使用
- chapter03_列表的使用
- chapter04_字典的使用
- chapter05_數字的使用
- chapter06_元組的使用
- chapter07_集合的使用
- chapter08_輸入輸出
- chapter09_控制流程
- chapter10_實例練習_登錄1
- chapter11_python函數入門
- chapter12_python中的類
- chapter13_輕松玩轉python中的模塊管理
- chapter14_掌握學習新模塊的技巧
- chapter15_通過os模塊與操作系統交互
- chapter16_子進程相關模塊(subprocess)
- chapter17_時間相關模塊(time & datetime)
- chapter18_序列化模塊(json)
- chapter19_加密模塊(hashlib)
- chapter20_文件的讀與寫
- chapter21_階段考核2_登錄
- chapter22_小小算法挑戰(排序&二分法)
- chapter23_用多線程來搞事!
- chapter24_HTTP接口請求(requests)
- chapter25_接口測試框架(pytest)
- chapter26_階段考核3_HTTP接口測試
- chapter27_HTML解析(pyquery)
- chapter28_階段考核4_爬蟲下載網易汽車
- chapter29_python中的那些編碼坑
- chapter30_MySQL數據庫操作
- chapter31 高級特性_迭代器與生成器
- chapter32 高級特性_裝飾器
- chapter33 高級特性_列表處理