一、閉包
????????在Python中,閉包(closure)是一個函數對象,即使在其詞法作用域外被調用,它仍然能訪問該作用域內的變量。閉包通過“捕獲”周圍作用域的變量,保持這些變量的狀態,即使在外部函數已經返回之后,這些變量仍然可以被訪問和修改。
????????
閉包是指:
- 一個嵌套函數。
- 這個嵌套函數引用了它的外部函數中的自由變量。
- 這個嵌套函數在其外部函數返回后,仍然可以訪問這些自由變量。
# 局部變量的銷毀問題def func():# 局部變量a = 10a = a+1print(a)func() # 函數調用結束后內部局部變量會自動銷毀
func() # 第二次調用函數時,會重新定義局部變量,重新計算print('---------------------------')
# 使用閉包可以將局部變量保存下來,每次調用函數時,使用同一個局部變量操作
# 閉包的格式是函數的嵌套定義
def func1():# 定義局部變量a = 10def func2():# 內部聲明局部變量nonlocal aa = a+1print(a)# 將內部定義的函數名返回return func2f2 = func1() # f2=func2
# 使用加法計算
f2()
f2()
相關概念:
- 嵌套函數(Nested Functions):在一個函數內部定義另一個函數。
- 自由變量(Free Variables):在閉包中使用的外部變量,這些變量并不是在閉包中定義的,但被閉包引用。
- 作用域(Scope):變量的可見范圍。在Python中,通常有四種作用域:局部(Local)、嵌套(Enclosing)、全局(Global)和內建(Built-in),簡稱LEGB規則。
閉包的特性
閉包有以下幾個重要特性:
- 狀態保持:閉包能夠保持它創建時的狀態。這意味著即使在外部函數的執行已經結束后,內部函數仍然可以訪問其作用域內的變量。
- 私有化變量:閉包常用于創建私有變量,因為這些變量只能通過閉包內部的函數進行訪問和修改,外部無法直接訪問。
閉包的實際應用
- 計數器:
def make_counter():count = 0def counter():nonlocal countcount += 1return countreturn countercounter1 = make_counter()
print(counter1()) # 輸出: 1
print(counter1()) # 輸出: 2counter2 = make_counter()
print(counter2()) # 輸出: 1
- 訪問控制:
def create_account(initial_balance):balance = initial_balancedef get_balance():return balancedef deposit(amount):nonlocal balancebalance += amountreturn balancereturn get_balance, depositget_balance, deposit = create_account(100)
print(get_balance()) # 輸出: 100
print(deposit(50)) # 輸出: 150
print(get_balance()) # 輸出: 150
二、裝飾器
????????裝飾器(Decorator)是Python中的一種設計模式,允許在不修改函數或方法定義的情況下,動態地給函數或方法增加功能。裝飾器本質上是一個高階函數(即接受函數作為參數或返回一個函數的函數),它返回一個新的函數,這個新函數通常對原函數進行了某種修改或擴展。
# 使用閉包定義裝飾器
def func1(f):# 外部函數定義接受參數,參數的類型要求是其他函數# f需要接受其他函數,就是需要裝飾修改邏輯的函數def func2():# 調用之前增加登錄判斷print('登錄成功')# 調用需要修改執行的函數f()# 返回內部函數return func2# 支付功能已經編寫完成,不能再隨意修改,如果此時需要再支付中增加一個登錄判斷如何實現
def pay():print('支付')
# 調用裝飾器
f2 = func1(pay) # f=pay f2 = func2
f2()def order():print('下單')
-
被裝飾的函數數據返回
def login(f):"""登錄裝飾器:param f: 接收被裝飾的函數:return:"""def inner(name, password):# 編寫登錄邏輯if name == '張三':if password == '123456':print('登錄成功')# 登錄成執行被裝飾的函數# 可以給傳遞數據和接收返回值res= f(1000)print(res)else:print('密碼錯誤')else:print('用戶名錯誤')return innerdef pay(price):print('訂單支付邏輯')print(f'支付金額{price}')return '支付成功'# 使用裝飾器裝飾支付函數
f = login(pay)
# f = inner
f('張三','123456')
-
采用語法糖格式使用裝飾器
-
語法糖格式 @裝飾器函數名
-
def login(f):"""登錄裝飾器:param f: 接收被裝飾的函數:return:"""def inner(name, password,price):# 編寫登錄邏輯if name == '張三':if password == '123456':print('登錄成功')# 登錄成執行被裝飾的函數res= f(price)print(res)else:print('密碼錯誤')else:print('用戶名錯誤')return inner# 使用語法糖
@login
def pay(price):print('訂單支付邏輯')print(f'支付金額{price}')return '支付成功'# 調用被裝飾的函數
# 此時pay函數變成了inneer函數
pay('張三','123456',1000)