python 裝飾器,高階與運用

2022-05-11 14:00:35 字數 3176 閱讀 9505

小 tips

寫遞迴函式的章節提到過,當函式不斷呼叫自身,直到被pycharm發現丟擲異常。實際上是因為棧溢位。

什麼是棧溢位呢?

python中只要呼叫乙個函式,函式中自己呼叫自己,每次呼叫都會放到記憶體中反覆遞迴,但是當原函式沒結束時(就是說沒有設定遞迴結束標示),遞迴就不會結束,直到記憶體被用完,棧溢位。

另外遞迴的效能是特別不好的,所以一般是不使用遞迴函式去編寫功能。

在進入裝飾器之前,先講解閉包函式的概念。

函式中呼叫函式本身,那麼在函式中可不可以定義乙個函式呢?

需求,如何函式外部呼叫內部定義的函式

問題引入,什麼是閉包?

閉包的概念:

函式中巢狀乙個函式

外層函式返回內層函式的變數名

內層函式對外部作用域有乙個非全域性變數的引用

來乙個最簡單的閉包案例

def login():

print("登入")

num = 100 # 這是個全域性變數

def func():

print("-----func被呼叫")

num =101 # 非全域性變數,因為命名空間在外層函式中(相較於內層被巢狀函式而言)

def count_book():

print(num) # 內部函式對外部作用域有乙個非全域性的引用

print("函式內部巢狀的函式")

return count_book # 外層函式返回的是內層函式的變數名

# 進行呼叫

res = func() # 通過return返回函式內部的函式,然後使用

res()

# 或者

func()() # 這樣的方式也可以訪問到內部函式

函式裡面定義的函式,相較於外部而言是乙個區域性變數,外部是無法訪問函式內部的函式的。

閉包函式會將傳入的區域性變數儲存在__closure__中,記錄的是非全域性變數,且從外部函式的__clourse__是訪問不到的。

#閉包有什麼作用?

def func(num,b):

def count_book():

print(num)

print(b)

print("這個是閉包函式")

return count_book

res = func([1,2,3],"python")

print(res.__closure__) # 閉包函式會將傳入的區域性變數儲存在__closure__中

# 記錄的是非全域性變數,且從外部函式的__closure__是訪問不到的

print(func.__closure__)

# 達成資料鎖定 從而不管外部環境發生任何變化,內部的變數都不會發生變化

接下來開始今天的硬菜,裝飾器的學習。

所謂開放封閉原則,是一種程式設計規範,軟體實體應該是可擴充套件,而不可修改的,也就是說,對擴充套件是開放的,而對內部原碼的修改是封閉的。

裝飾器則是這一理念的實現,即在不修改原方法的前提下進行功能的擴充套件

裝飾器的應用場景

登入驗證,函式執行時間統計,執行函式之前進行的操作,執行函式之後做的清理操作(有點類似unittest,pytest的前置後置方法)

來看乙個例項

# 實現乙個裝飾器

username ="python"

pwd = "123"

def login(func): # 將閉包函式改造成裝飾器,需要往函式內傳入乙個函式 裝飾那個函式就傳入那個函式

def fun():

user = input("請輸入賬號")

password = input("請輸入密碼")

if username == user and pwd==password:

func() # 賬號和密碼都正確的時候才呼叫被裝飾的函式

else:

print("賬號或者密碼錯誤")

return fun

# 裝飾器中的形參func 就相當於被裝飾的函式物件,

# 希望給被裝飾的函式新增什麼功能(或者什麼時候想要呼叫被裝飾函式,

@login

def index():

print("這個是**的首頁")

# index() # 加入需求是登入之前先進行驗證賬號,要求不能修改登入原函式,新增乙個驗證

# closure__ = index.__closure__

# 裝飾器其實就是乙個閉包

呼叫原理:

@login 新增在index()方法上--->login(index) 即將方法作為乙個引數傳入了login方法中

然後進入login函式中的內部函式執行,首先進行驗證,驗證通過則呼叫index函式,即func形參代表的傳入的index方法。

不通過則輸出對應字串,最後將內部函式返回,以供呼叫者使用

有參裝飾器

需求:列印兩個數相加,然後列印相乘,相除的結果,要求不能修改原方法**

def add_num(a,b): # 原函式

print('相加:',a+b)

def add(func):

def fun(a, b): # 傳參先進入這裡

print('相乘',a*b)

print('相除',a/b)

func(a,b) # 此處為被修飾的原函式的呼叫 如果忘記此處,原函式將不會被執行

return fun

@add

add_num(1,2)

呼叫原理:

@add 加在add_num頭上等價於---->add(add_num(1,2))--->進入add裝飾器方法中的內部函式

然後執行內部函式中的邏輯,通過形參func去呼叫傳進來的實參add_num去執行原函式。

但是原函式有參,所以func(a,b)傳入a,b形參最後返回內部函式給呼叫者,完成整個呼叫。

再高階,可傳參和不可傳參我全都要

再再高階,裝飾乙個類

python高階裝飾器 Python裝飾器高階

對帶引數的函式進行裝飾 對帶引數的函式進行裝飾,內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件 def deco func def deco a,b print before myfunc called.ret func a,b print after myfunc calle...

python高階 裝飾器

1.1 裝飾器 裝飾器的作用 在不改變原函式的情況下給函式增加功能 裝飾器由閉包和語法糖組成 1.2 閉包 閉包特點 外部函式巢狀內部函式 內部函式可以訪問並且儲存外部函式的變數 外部函式返回內部函式的引用 有以上三個特點的函式就稱為閉包 閉包的例子 def func1 a def func2 b ...

python高階 裝飾器

1.1 裝飾器 裝飾器的作用 在不改變原函式的情況下給函式增加功能 裝飾器由閉包和語法糖組成 1.2 閉包 閉包特點 外部函式巢狀內部函式 內部函式可以訪問並且儲存外部函式的變數 外部函式返回內部函式的引用 有以上三個特點的函式就稱為閉包 閉包的例子 def func1 a def func2 b ...