Python高階 -- 11 閉包、裝飾器
一、閉包
1、什麼是閉包
# 定義一個函式
def test(number):
"""
在函式內部再定義一個函式,並且這個函式用到了外邊函式的變數,
同時,外部函式的返回值是內部函式的引用
那麼將這個函式(內部定義的那個函式)以及用到的一些變數稱之為閉包
"""
def test_in(number_in):
print("in test_in 函式, number_in is %d" % number_in)
return number + number_in
# 其實這裡返回的就是閉包的結果
return test_in
# 給test函式賦值,這個20就是給引數number
ret = test(20)
# 注意這裡的100其實是給test函式內部定義的test_in函式的引數number_in賦值
# ret是test函式的返回值,即返回的是test函式內部的定義的test_in函式的引用
print(ret(100))
#注 意這裡的200其實給引數number_in
print(ret(200))
二、裝飾器
1、先理解下面程式碼
#### 第一波 ####
def foo():
print('foo')
foo # 表示是函式的引用
foo() # 表示執行foo函式
#### 第二波 ####
def foo():
print('foo')
foo = lambda x: x + 1
foo() # 執行lambda表示式,而不再是原來的foo函式,因為foo這個名字被重新指向了另外一個匿名函式
# 以上程式碼是將lambda表示式賦值給了foo變數,此時,執行foo(),代表的是執行lambda表示式
函式名僅僅是個變數,只不過指向了定義的函式而已,所以才能通過 函式名()呼叫;如果 變數被修改了,即函式名=xxx ,那麼當在執行 函式名() 時,呼叫的就不是之前的那個函式了,而是被賦值之後的函式
2、裝飾器
使用閉包引入裝飾器概念
def validation(fun):
# 定義一個內部函式
def doValidation():
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
fun()
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
def test():
print("test方法中加入校驗")
"""
例項化外部函式,引數是其他函式(test函式)的引用
由於外部函式(validation)中還有一個函式定義,
因此,例項化外部函式的時候,會定義一個內部函式,返回的是內部函式的引用
而由於,在內部函式中使用其他函式(test函式)的引用來例項化了一個其他函式(test函式)物件,
因此,例項化內部函式的時候,會進行其他函式(test函式)的例項化操作
"""
test = validation(test) # 此時的test是內部函式的引用
"""
執行內部函式,由於內部函式中其他函式(test)的例項化操作
因此,在內部函式中所執行的程式碼(本例中為列印操作)可以放在其他函式(test)前或者後進行操作
即:達到了在執行其他函式前(或者後)進行校驗的目的
"""
test()
"""
執行結果:
放在 fun() 之前的內容是屬於前置校驗
test方法中加入校驗
放在 fun() 之後的內容是屬於後置校驗
"""
使用裝飾器來進行上述操作的程式碼:
def validation(fun):
# 定義一個內部函式
def doValidation():
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
fun()
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
@validation
def test():
print("test方法中加入校驗")
"""
例項化外部函式,引數是其他函式(test函式)的引用
由於外部函式(validation)中還有一個函式定義,
因此,例項化外部函式的時候,會定義一個內部函式,返回的是內部函式的引用
而由於,在內部函式中使用其他函式(test函式)的引用來例項化了一個其他函式(test函式)物件,
因此,例項化內部函式的時候,會進行其他函式(test函式)的例項化操作
⭐⭐⭐在其他函式上使用 @外部函式名 ,這種方式可以替代以下程式碼來進行test方法執行前後的校驗
test = validation(test) # 返回值是內部函式的引用
"""
"""
執行內部函式,由於內部函式中其他函式(test)的例項化操作
因此,在內部函式中所執行的程式碼(本例中為列印操作)可以放在其他函式(test)前或者後進行操作
即:達到了在執行其他函式前(或者後)進行校驗的目的
"""
test()
"""
執行結果:
放在 fun() 之前的內容是屬於前置校驗
test方法中加入校驗
放在 fun() 之後的內容是屬於後置校驗
"""
解釋:在方法上加上 @其他方法名 的方式即為裝飾器的使用,而其他方法是一個包含了內部函式的一個函式,在內部函式中有方法的例項化操作,這種方式就達到了裝飾器的效果
3、對帶有引數的方法進行裝飾器
不使用裝飾器的寫法:
def validation(fun):
# 定義一個內部函式
def doValidation(args):
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
fun(args)
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
def test(args):
print("test方法中加入校驗 %s" % args)
test = validation(test) # 返回值是是內部函式的引用
test(100)
使用裝飾器的寫法:
def validation(fun):
# 定義一個內部函式
def doValidation(args):
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
fun(args)
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
@validation
def test(args):
print("test方法中加入校驗 %s" % args)
# test = validation(test) # 返回值是是內部函式的引用
test(100)
4、不定長引數的函式裝飾器
def validation(fun):
# 定義一個內部函式
def doValidation(*args, **kwargs):
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
fun(*args, **kwargs)
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
@validation # test = validation(test) 返回值是是內部函式的引用
def test(num, *args, **kwargs):
print("test方法中引數1 %s" % num)
print("test方法中引數2 : " , args)
print("test方法中引數3 : " , kwargs)
test(100)
print("-" * 50)
test(100, 200)
print("-" * 50)
test(100, 200, 300, name='李四')
"""
執行結果:
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : ()
test方法中引數3 : {}
放在 fun() 之後的內容是屬於後置校驗
--------------------------------------------------
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : (200,)
test方法中引數3 : {}
放在 fun() 之後的內容是屬於後置校驗
--------------------------------------------------
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : (200, 300)
test方法中引數3 : {'name': '李四'}
放在 fun() 之後的內容是屬於後置校驗
"""
5、帶有返回值的函式的裝飾器
帶有返回值的函式的裝飾器亦是通用裝飾器(可變引數,有返回值的裝飾器)的寫法:
def validation(fun):
# 定義一個內部函式
def doValidation(*args, **kwargs):
# 執行前置校驗
print("放在 fun() 之前的內容是屬於前置校驗")
# 執行fun函式
return fun(*args, **kwargs)
# 執行後置校驗
print("放在 fun() 之後的內容是屬於後置校驗")
# 外部函式返回值是內部函式的引用
return doValidation
@validation # test = validation(test) 返回值是是內部函式的引用
def test(num, *args, **kwargs):
print("test方法中引數1 %s" % num)
print("test方法中引數2 : " , args)
print("test方法中引數3 : " , kwargs)
return "OK"
ret = test(100)
print(ret)
print("-" * 50)
ret = test(100, 200)
print(ret)
print("-" * 50)
ret = test(100, 200, 300, name='李四')
print(ret)
"""
執行結果:
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : ()
test方法中引數3 : {}
OK
--------------------------------------------------
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : (200,)
test方法中引數3 : {}
OK
--------------------------------------------------
放在 fun() 之前的內容是屬於前置校驗
test方法中引數1 100
test方法中引數2 : (200, 300)
test方法中引數3 : {'name': '李四'}
OK
"""
6、多個裝飾器對一個函式進行裝飾
def zhuangshi_1(fun):
print("定義裝飾1")
# 定義一個內部函式
def neibu_1(*args, **kwargs):
# 執行前置校驗
print("執行 zhuangshi_1 中的裝飾內容")
# 執行fun函式
return fun(*args, **kwargs)
# 外部函式返回值是內部函式的引用
return neibu_1
def zhuangshi_2(fun):
print("定義裝飾2")
# 定義一個內部函式
def neibu_2(*args, **kwargs):
# 執行前置校驗
print("執行 zhuangshi_2 中的裝飾內容")
# 執行fun函式
return fun(*args, **kwargs)
# 外部函式返回值是內部函式的引用
return neibu_2
@zhuangshi_1
@zhuangshi_2
def test():
pass
test()
"""
執行結果:
定義裝飾2
定義裝飾1
執行 zhuangshi_1 中的裝飾內容
執行 zhuangshi_2 中的裝飾內容
解釋:
定義裝飾器的時候,先執行離方法最近的裝飾器的定義
執行裝飾器的時候,先執行最上層的裝飾器
"""
7、多個裝飾器裝飾一個函式的應用
def html_1(func):
def td():
return "<td>" + func() +"</td>"
return td
def html_2(func):
def p1():
return "<p1>" + func() + "</p1>"
return p1
@html_1
@html_2
def test():
return "hello world"
print(test())
"""
執行結果:
<td><p1>hello world</p1></td>
"""
8、帶有引數的裝飾器
def parent(arg):
def validation(func):
def call_func(*args, **kwargs):
if arg == 1:
print("level 1")
elif arg == 2:
print("level 2")
return func()
return call_func
return validation
"""
⭐⭐⭐:帶有引數的裝飾器呼叫的時候:
首先會將引數當作實參,傳遞到裝飾器中,進行第一層函式的呼叫,並返回第二層函式的引用;
然後,將第二層函式的引用當作真正的裝飾器,進行裝飾
以下呼叫中,首先@parent(1)會先執行parent方法,把引數1傳遞進去,返回的是validation的引用
然後,使用validation作為真正的裝飾器,對test1方法進行裝飾
"""
@parent(1)
def test1():
return "OK"
test1()
@parent(2)
def test2():
return "OK"
test2()
9、用類對函式進行裝飾
class Test(object):
def __init__(self, func):
self.func = func
def __call__(self):
print("對函式進行裝飾的方法")
return self.func()
@Test
def demo():
return "呵呵"
print(demo())
相關文章
- python高階-閉包-裝飾器Python
- Python進階之閉包和裝飾器Python
- Python閉包與裝飾器Python
- 【python】閉包與裝飾器Python
- python 閉包和裝飾器Python
- Python:從閉包到裝飾器Python
- Python 的閉包和裝飾器Python
- python的裝飾器和閉包Python
- python_August(閉包、裝飾器)Python
- Python裝飾器高階用法Python
- Python 中的閉包與裝飾器Python
- python的閉包及裝飾器薦Python
- Python高階--閉包Python
- Python提高:關於閉包和裝飾器Python
- Python函式裝飾器高階用法Python函式
- Python 簡明教程 --- 22,Python 閉包與裝飾器Python
- 閉包函式,裝飾器詳解函式
- Python Enclosing作用域、閉包、裝飾器話聊下篇Python
- 函式物件、裝飾器、閉包函式函式物件
- 13. 閉包函式與裝飾器函式
- Python3之從遞迴到閉包再到裝飾器Python遞迴
- Python學習之路26-函式裝飾器和閉包Python函式
- 進階11 閉包、定時器、BOM定時器
- 裝飾器中閉包之加認證功能
- ES 6 裝飾器與 React 高階元件React元件
- day11(python)裝飾器Python
- python裝飾器2:類裝飾器Python
- 高階玩法之類的裝飾器的應用
- js 閉包 基礎 示例 高階JS
- 深入理解閉包,裝飾器,深拷貝淺拷貝
- Python裝飾器探究——裝飾器引數Python
- python進階(12)閉包Python
- Python 裝飾器Python
- Python裝飾器Python
- 裝飾器 pythonPython
- 剖析 Python 面試知識點(一): 魔法方法、閉包/自省、裝飾器/生成器Python面試
- 《流暢的Python》 讀書筆記 第7章_函式裝飾器和閉包Python筆記函式
- Python 裝飾器裝飾類中的方法Python