裝飾器語法糖運用
前言:函數名是一個特性的變量,可以作為容器的元素,也可以作為函數的參數,也可以當做返回值。
閉包定義:
內層函數對外層函數(非全局)變量的引用,這個內層函數就可以成為閉包
在Python中我們用
__closure__
來檢查函數是否是閉包def func1():name = '張三'def func2():print(name) # 能夠訪問到外層作用域的變量func2()print(func2.__closure__) # (<cell at 0x1036c7438: str object at 0x10389d088>,)func1() print(func1.__closure__) # None
裝飾器
前言:軟件設計原則:開閉原則,又稱開放封閉原則
- 指對擴展代碼的功能是開放的,但對修改源代碼是封閉的,
def create_people():print('女媧真厲害,捏個泥吹口氣就成了人!')def a(func):def b():print('灑點水')func()return bret = a(create_people) ret()
通過裝飾器語法等同于
def a(func):def b():print('灑點水')func()return b@a # 裝飾器語法糖的作用就是上述函數ret() def create_people():print('女媧真厲害,捏個泥吹口氣就成了人!')create_people()
裝飾帶返回值的函數,即return出被裝飾函數的執行結果
def foo(func): # 接收的參數是一個函數名def bar(): # 定義一個內層函數print("這里是新功能...") # 新功能r = func() # 在內存函數中拿到被裝飾函數的結果return r # 返回被裝飾函數的執行結果return bar# 定義一個有返回值的函數 @foo def f1():return '嘿嘿嘿'# 調用被裝飾函數 ret = f1() # 調用被裝飾函數并拿到結果 print(ret)
裝飾帶參數的函數
def func1(func): # 接收的參數為一個函數名def inner(*args, **kwargs): # 這里需要定義和被裝飾函數相同的參數print("新功能") # 新功能ret = func(*args, **kwargs) #被裝飾的函數和參數print("新功能") return retreturn inner# 定義一個需要倆個參數的函數 @func1 def func(a, b):return a + bret = func(3, 5) print(ret)
帶參數的裝飾器 即在裝飾器外在寫一層函數,從而使其帶參數
def d(a=None): # 定義一個外層函數,給裝飾器傳參數def func1(func): # 接收的是一個函數名def inner(*args, **kwargs): # 被裝飾的函數,和參數if a:print(f"歡迎來到{a}") #添加新功能else:print("歡迎來到王者榮耀") func(*args, **kwargs)return innerreturn func1# @d("英雄聯盟") # def func(st): # print(st) # func("敵軍還有三十秒到達戰場")# 歡迎來到英雄聯盟# 敵軍還有三十秒到達戰場@d() def func(st):print(st) func("敵軍還有三十秒到達戰場") # 歡迎來到王者榮耀 # 敵軍還有三十秒到達戰場
裝飾器修復技術
定義:被裝飾的函數最終都會失去本來的__doc__等信息, Python給我們提供了一個修復被裝飾函數的工具。
from functools import wraps #導入 print(f1.__doc__) print(f1.__name__)
多個裝飾器裝飾同一函數
from functools import wrapsdef wrapper2(func):@wraps(func)def inner(*args, **kwargs):r = func(*args, **kwargs)return f"<2>{r}</2>"return innerdef wrapper1(func):@wraps(func)def inner(*args, **kwargs):r = func(*args, **kwargs)return f"<1>{r}</1>"return inner@wrapper2 @wrapper1 def func(a):return aprint(func("Hello World!!")) #<2><1>Hello World!!</1></2>
def foo1(func):print("d1")def inner1():print("inner1")return "<i>{}</i>".format(func())return inner1def foo2(func):print("d2")def inner2():print("inner2")return "<b>{}</b>".format(func())return inner2@foo1 @foo2 def f1():return "Hello Andy"# f1 = foo2(f1) ==> print("d2") ==> f1 = inner2 # f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1ret = f1() # 調用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i> print(ret)
類裝飾器
class D(object):def __init__(self, a=None):self.a = aself.mode = "裝飾"def __call__(self, *args, **kwargs):if self.mode == "裝飾":self.func = args[0] # 默認第一個參數是被裝飾的函數self.mode = "調用"return self# 當self.mode == "調用"時,執行下面的代碼(也就是調用使用類裝飾的函數時執行)if self.a:print("歡迎來到{}頁面。".format(self.a))else:print("歡迎來到首頁。")self.func(*args, **kwargs)@D() def index(name):print("Hello {}.".format(name))@D("電影") def movie(name):print("Hello {}.".format(name))if __name__ == '__main__':index('張三')movie('張三')
裝飾類
# 定義一個類裝飾器 class D(object):def __call__(self, cls):class Inner(cls):# 重寫被裝飾類的f方法def f(self):print('Hello 張三.')return Inner@D() class C(object): # 被裝飾的類# 有一個實例方法def f(self):print("Hello world.")if __name__ == '__main__':c = C()c.f()