閉包函數自己是一個函數,是把閉包函數內部的函數 + 函數內部的變量包裹起來,而後經過返回值 返回出去。閉包
閉包函數必須得符合函數嵌套app
# 閉包函數:自己是一個函數,讓其調用更方便 # 定義 # 把一個函數名 + 變量 封裝成一個函數 返回(return)出去 def out_fun(url): # url = "qinyj" def iner_fun(): print(url) return iner_fun a = out_fun("url") a()
如今有一個函數,老闆有一個需求,想在這個函數上加一個計時功能,就是計算這個函數執行時間,需求吩咐下去,某某公司的3個運維開發開始思考了。。。運維
def index(): print(from index)
第一我的 小青開始作。。。他的方式是修改源代碼:函數
import time def index(): start = time.time() print("from index") time.sleep(1) end = time.time() print(end - start) index()
from index 1.0080575942993164
第二我的 小杰開始作。。。他的方式是在調用的時候計算時間學習
import time def index(): print("from index") time.sleep(1) start = time.time() index() end = time.time() print(end - start)
from index 1.0000572204589844
第三我的 小強開始作。。。他用了一個很是牛逼的看不懂的騷操做。。url
import time def index(): print("from index") def time_count(func): def inner(): start = time.time() func() time.sleep(1) end = time.time() print(end - start) return inner index = time_count(index) index()
from index 1.0000572204589844
好了,如今三我的已經所有作完,老闆該驗收了,把他們三我的叫到會議室。。。code
指明瞭小強作的很是不錯!另外兩個向他學習,小強作的方式就是裝飾器ip
裝飾器:自己是一個函數,給已有的函數加功能utf-8
不改變源代碼
不改變其調用方式
剛纔只有小強的代碼符合上面規定
# v1 實現最簡單的裝飾器 import time def index(): """被裝飾的函數""" print('index') time.sleep(1) # time_count裝飾器:對被裝飾函數計時 def time_count(func): # func纔是真正的index """裝飾器""" def wrapper(): start = time.time() func() end = time.time() print(end - start) return wrapper index = time_count(index) # index == wrapper index() # wrapper()
# v2:帶返回值 import time def index(): """被裝飾的函數""" print('x',x) print('index') time.sleep(1) return 'index' # time_count裝飾器:對被裝飾函數計時 def time_count(func): # func纔是真正的index """裝飾器""" def wrapper(): start = time.time() res = func() # index() end = time.time() print(end - start) return res return wrapper index = time_count(index) # index == wrapper res = index() # wrapper() print(res)
# v3:加參數 import time def index(x,y,z=10): """被裝飾的函數""" print('x',x) print('index') time.sleep(1) return 'index' # time_count裝飾器:對被裝飾函數計時 def time_count(func): # func纔是真正的index """裝飾器""" def wrapper(*args,**kwargs): # (10, 20) # *args和**kwargs接收了全部的參數 start = time.time() res = func(*args,**kwargs) # index() # *(10,20) # *args和**kwargs打散參數傳給真正的index end = time.time() print(end - start) return res return wrapper index = time_count(index) # index == wrapper res = index(10,20,320) # wrapper() print(res)
用來裝飾函數的,它本質是函數
不改變函數源代碼
不改變函數調用方式
若是實在理解不了,就記住裝飾器模板:
from functools import wraps def deco(func): @wraps(func) def wrapper(*args, **kwargs): # 要加什麼功能就加上去 res = func(*args, **kwargs) return res return wrapper
這裏提到了一個wraps,其實Python裝飾器(decorator)在實現的時候,被裝飾後的函數其實已是另一個函數了(函數名等函數屬性會發生改變),爲了避免影響,Python的functools包中提供了一個叫wraps的decorator來消除這樣的反作用。寫一個decorator的時候,最好在實現以前加上functools的wrap,它能保留原有函數的名稱和docstring。
廢話很少說,上倆例子就能搞明白!
實例一:
不加wraps
# -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__) # 執行結果: # ('wrapper', 'decorator')
實例二:
加wraps
# -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__) # 執行結果: # ('example', 'Docstring')
warps 做用: 消除或修復(被裝飾後的函數名等屬性的改變)反作用
在被裝飾的函數上 加上 @裝飾器函數名,目的是爲了讓代碼更加簡潔。
@time_count def index(x,y,z=10): """被裝飾的函數""" print('x',x) print('index') time.sleep(1) return 'index'
三層裝飾器就是給裝飾器加參數,在原有的兩層裝飾器上再嵌套一層函數,利用閉包的思想,把函數變量和函數名返回出去。
username_list = [] def sanceng(role): def login_deco(func): def wrapper(*args, **kwargs): if username_list: print('已經登陸,請勿重複登陸') res = func(*args, **kwargs) return res username_inp = input('請輸入用戶名:') pwd_inp = input('請輸入密碼:') with open(f'{role}_info.txt', 'r', encoding='utf8') as fr: for user_info in fr: username, pwd = user_info.strip().split(':') if username_inp == username and pwd_inp == pwd: print('登陸成功') username_list.append(username) res = func(*args, **kwargs) return res else: print('登陸失敗') return wrapper return login_deco @sanceng('admin') def index(x, y): print('index') print('x,y', x, y) return 123 res = index(10, 20) print(res)