首先我們應該知道一件事:函式的定義域跟定義位置有關係,而跟呼叫位置沒有關係。閉包函式:
定義:內層函式對外層函式而非全域性變數的引用,就叫做閉包函式
閉包會一直存在在記憶體中,不會因為函式執行結束而被釋放
先看個例子:
defouter():
num = 1
definner():
nonlocal num
num += 1
(num)
return
inner
a = outer() #
此時a為乙個函式
a() #
2a() #
3a() #
4
num會一直存在,不會因為外層函式結束而釋放。這就是閉包函式,可以在任何地方呼叫
閉包的意義
意義:返回的函式物件,不僅僅是乙個函式物件,在該函式外還包裹了一層作用域,
這使得無論在何處呼叫,優先使用自己外層包裹的作用域
裝飾器:閉包函式的一種應用場景
裝飾器原則:1,不修改物件的源**,2,不修改物件的呼叫方式,
目標:在遵循1,2的前提下,為被裝飾物件新增上新的功能
假如我們有這樣乙個需求,測試乙個函式所用的時間
importtime
deffunction():
time.sleep(1)
print('
函式執行')
start_time =time.time()
function()
end_time =time.time()
print("
函式的執行時間%s
" %(end_time -start_time))
#但此時多了幾行**,再次修改
deffunction():
time.sleep(1)
print('
函式執行')
deftimeer():
start_time =time.time()
function()
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
timeer()
#我們要想也計算其他函式的時間怎麼辦?
deffunction1():
time.sleep(1)
print('
函式執行')
deftimeer(function):
start_time =time.time()
function()
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
timeer(function1)
#又有了新的要求,我們想要在不改變原函式的呼叫方式來修改
#可以用閉包來實現
deffunction2():
time.sleep(1)
print('
函式執行')
deftimeer(function):
definner():
start_time =time.time()
function()
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
return
inner
function2 =timeer(function2)
function2()
#這樣就可以在不修改函式呼叫方式的情況下增加功能
#python有乙個語法糖的功能,例子如下
deftimeer(function):
definner():
start_time =time.time()
function()
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
return
inner
@timeer
#相當於:function2 = timeer(function2)
deffunction2():
time.sleep(1)
print('
函式執行')
function2()
上述就是裝飾器的基本方式新的問題又來了,我們寫的函式有引數怎麼辦呢?
我們直接給inner加上引數就好了啊
注意,此時引數應該怎麼加,應該保證同時適用於有引數和無引數的函式
因為我們不知道函式有幾個引數,所以應該用不定長引數
deftimeer(function):
def inner(*args,**kwargs):
#這樣函式沒有引數也可以用
start_time =time.time()
function(*args,**kwargs)
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
return
inner
@timeer
deffunction2():
time.sleep(1)
print('
函式執行')
@timeer
defadd_num(num1,num2):
print(num1 +num2)
function2()
add_num(3,5)
不知道大家發現沒有,我們還有乙個問題沒有解決,對了,那就是函式的返回值的問題,我們怎麼給有返回值的函式加裝飾器呢?
我們從前面可以知道,我們加了裝飾器,是會執行裝飾器內部的inner函式
那麼我們給inner函式加上返回值就好了啊,看**:
deftimeer(function):
def inner(*args,**kwargs):
#這樣函式沒有引數也可以用
start_time =time.time()
res = function(*args,**kwargs)
#此處用乙個變數來接受函式的返回值。
end_time =time.time()
print("
函式的執行時間%s
" % (end_time -start_time))
#函式的最後應該有返回值,而且這個返回值必須是function函式執行後的返回值,
#那麼我們就知道該怎麼寫**了,我們用乙個變數來接受函式function執行後的返回值就好了啊
return
res
#在此處返回
return
inner
@timeer
defmax_num(num1,num2):
if num1 >num2:
return
num1
else
:
return
num2
print(max_num(3,5))
defouter(function):
def inner(*args,**kwargs):
#函式執行前你想要做的
res =function()
#函式執行後你想要做的
return
res
return inner
那麼到此處我們就已經掌握了裝飾器的內容,上邊是乙個框架
python基礎之閉包函式和裝飾器
補充 全域性變數宣告及區域性變數引用 python引用變數的順序 當前作用域區域性變數 外層作用域變數 當前模組中的全域性變數 python內建變數 global關鍵字用來在函式或其他區域性作用域中使用全域性變數,宣告後可以在其他作用於中修改和使用 x 1 全域性賦值變數 def foo globa...
python裝飾器,閉包函式
閉包函式 在函式a內部定義另外乙個函式b,之後b作為a的返回值直接被返回。此時函式b稱為a的閉包函式。在閉包函式b中如果使用a函式中定義的變數,此時a函式中被定義的變數會被臨時儲存,直到b函式呼叫結束時該變數才會被系統收回,從而實現a中變數延遲釋放 例如global 宣告的變數屬於全域性變數,此時在...
函式裝飾器和閉包
裝飾器是可呼叫的物件,其引數是另乙個函式 被裝飾的函式 裝飾器可能會處理被裝飾的函式,然後把它返回,或者將其替換成另乙個函式或可呼叫物件。裝飾器通常把函式替換成另乙個函式 defdeco func definner print running inner return inner deco def ...