1. 程式人生 > 其它 >今日總結——閉包和裝飾器

今日總結——閉包和裝飾器

今日內容總結

一、閉包函式

二、閉包函式的實際應用

三、裝飾器簡介

四、簡易版本裝飾器

五、進階版本裝飾器

六、完整版本裝飾器

七、裝飾器模板(很重要)

八、裝飾器語法糖

九、裝飾器修復技術

一、閉包函式

# 閉包函式的兩大特徵
1、閉:定義在函式內部的函式
2、包:內部函式使用了外層函式名稱空間中的名字
eg:
 def outer():
    x = 111
    def inner():
        print('form outer>>>inner',x)
    return inner
x = 222  # 結果和這個x = 222沒有關係
res = outer()
res()  # 111

二、閉包函式實際應用

# 閉包函式是給函式傳參的另外一種方式
函式體傳參的方式:
 1、形參:
 def index(username):
     print(username)
 函式體程式碼需要什麼就可以在形參中寫什麼
 index('owen')
    
 2、閉包
 def outer():
        username = 'owen'
        def index():
            print(username)
        return index
 res = outer()
 res()  # owen
 #當這個閉包裡只寫了Owen,那就會一直使用owen
    
 def outer(username):
    def index():
        print(username)
    return index
res = outer('mary') # 形參username與值mary臨時繫結到outer區域性名稱中
res()  # mary
res1 = outer('owen')# 形參username與值owen臨時繫結到outer區域性名稱空間裡面
res1()  # owen

# 想要修改引數,就重新定義一個值,進行重新繫結

三、裝飾器簡介

裝飾器的本質:
    例如給函式index裝飾
    在不改變index原有的'呼叫方式'和'內部程式碼'的情況下給index新增新的功能
    
裝飾器的原則:
   """對外擴充套件開放,對修改封閉"""
import time(呼叫模組)
print(time.time())  # 1647589902.705415
# 獲取的數字就是時間戳:1970年1月1日0時0分0秒距離剛剛程式碼執行間隔的秒數
time.sleep(3)  # 讓程式原地休眠三秒
print('hello world')
print(time.time())
# hello world
# 1647590604.362981
  • 統一函式的執行時間
import time
def index():
    time.sleep(3)
    print('from index')
start_time = time.time()  # 函式執行之前獲取的時間節戳
index()
end_time = time.time()  # 函式執行之後獲取一個時間戳
print(end_time - start_time)  # 用第二個時間戳減第一個時間戳,結果就是函式的執行時間

四、簡易版本裝飾器

'''給index函式增加了一個統計執行時間的功能'''
def index():
    time.sleep(1)
    print('from index')
start_time = time.time()  # 函式執行之前獲取一個時間戳
index()
end_time = time.time()  # 函式執行之後獲取一個時間戳
print(end_time - start_time)  # 兩個時間戳的差值就是函式的執行時間
# 這個只能給一個函式增加功能

import time
def index():
    time.sleep(1)
    print('from index')
def home():
    time.sleep(3)
    print('from home')
print(home)
def outer(func):
    def get_time():
        start_time = time.time()  # 函式執行之前獲取一個時間戳
        func()  # 呼叫了真正的index函式
        end_time = time.time()  # 函式執行之後獲取一個時間戳
        print(end_time - start_time)  # 兩個時間戳的差值就是函式的執行時間
    return get_time
home = outer(home)  # 狸貓換太子
home()
print(home)

五、進階版本裝飾器

# 解決的是引數問題
def out (func_name):  
    def get_time(*args, **kwargs):
        start_time = time.time()  # 開始獲取一個時間
        func_name(*args, **kwargs)
        end_time = time.time()  # 結束獲取一個時間
        print(end_time - start_time)
    return get_time
# 這個主要可以改變引數,引數的型別都可以

六、完整版裝飾器

# 解決的是返回值問題
import time
def index(username):
    time.sleep(3)
    return username
def outer(func_name):
    def get_time(*args, **kwargs):  # 可變長形參,什麼資料型別都可以
        start_time = time.time()
        res = func_name(*args, **kwargs)  # 執行真正的index函式
        end_time = time.time()
        print(end_time - start_time)
        return res  # 返回原函式的值,沒有的時候返回的是none
    return get_time
index = outer(index)
res = index('起飛')
print(res)

七、裝飾器模板

# 兄弟們,這才是關鍵
def outer(func_name):  # func_name用於接收被裝飾的物件(函式)
    def inner(*args, **kwargs):
        print('執行被裝飾函式之前 可以做的額外操作')
        res = func_name(*args, **kwargs)  # 執行真正的被裝飾函式
        print('執行被裝飾函式之後 可以做的額外操作')
        return res  # 返回真正函式的返回值
    return inner

八、裝飾器語法糖

# 語法糖內部原理
  1、使用時最好緊跟在被裝飾物件上面
  2、語法糖會自動將下面緊挨著的函式名床給@後面的函式呼叫
# 先定義一個outer函式
def outer(func_name):
    def inner(*args, **kwargs):
        print('執行函式之前的操作')
        res = func_name(*args, **kwargs)
        # 額外操作
        return res
    return inner
#  使用outer直接@加outer
@outer  # 等價於 index = outer(index)
def index(*args, **kwargs):
    print('from index')
print(index)   


@outer  # 等價於 home = outer(home)
def home(*args,**kwargs):
    print('from home')
print(home)

九、裝飾器修復技術

from functools import wraps  # 固定搭配
def outer(func_name):
    @wraps(func_name)  # wraps模組warps關鍵字可以把真函式的屬性提取出來,賦值給裝飾器,達到以假亂真的地步
    def inner(*args, **kwargs):
        print('執行被裝飾物件之前可以做的操作')
        res = func_name(*args, **kwargs)
        return res
    return inner
@outer
def home():
    '''這是函式的註釋'''
    print('from home')
home()
print(home)
help(home)
# 結果為
from home
<function home at 0x00000249C8FDFCA0>
Help on function home in module __main__: