1. 程式人生 > >Day59 Python--閉包&裝飾器

Day59 Python--閉包&裝飾器

一,函式知識點回顧

def func():
    pass

print(func)  #函式名對應記憶體地址

a = func  #可以賦值給變數
a()
 
def func2(arg):  #可以做引數
    arg()
func2(func)

def func3():  #可以做返回值
    def fun4():
        pass
    return func4

lis = [func,func2,func3,func4]  #可以做容器物件的元素
for i in lis:
    i()

 

二,閉包

  定義:如果一個內層函式包含了對外層函式變數的引用,那這個內層函式就是閉包

def wrapper(name):
    def inner():
        print(name) #相當內層函式的空間裡保留了name變數的引用並且指向當初傳入的實參
    return inner
ret = wrapper('123')  #當函式執行時,Python直譯器會開闢一塊記憶體(區域性名稱空間)來儲存這個函式裡面的內容,這個時候,Python直譯器才關注函式裡面變數名和值之間對應的關係,包括內層函式內的內容

del wrapper
ret()     # 指向inner的記憶體地址
wrapper('123')  #報錯:NameError: name 'wrapper' is not defined
閉包如何儲存區域性變數的資料
#靈魂三問1
def func1():
    num = 100
    def func2(arg):
        print(arg)
    func2(num)  #通過傳參的方式,向內層函式傳遞資料

func1()  

#靈魂三問2
def func1():
    num = 100
    def func2()
        print(num)  #內層函式的作用域裡沒有num,會自動往外層函式的作用域去找
    func2()

func1()

#靈魂三問3
def func1(num):
    
def func2(): print(num) #內層函式的作用域路沒有num,會自動往外層函式的作用域去找 func2() func1()
看起來好像很牛b的閉包靈魂三問
#內層函式+其外層函式變數的引用
def func1(name):
    def func2():
        print(name)
    return func2

ret = func1('alex')
ret()

#非閉包
def func1():
    def func2():
        def func3():
            def func4():
                pass
            return func4
        return func3
    return func2

ret1 = func1()  #func2
ret2 = ret1() #func3
ret3 = ret2() #func4
ret3()
閉包的變形

 

三,裝飾器初識 

#裝飾器的定義:
既不想直接修改原來的函式,也不想修改函式的呼叫方式,還要加新功能的時候,可以使用裝飾器
def wrapper(func): def inner(*args,**kwargs): print('新功能') func(*args,**kwargs) return inner
#global_func = wrapper(global_func) 內層的inner函式,引用了func,func -指向-> global_func
@wrapper  #相當於把被裝飾的函式當成引數傳給a,然後把返回值再賦值給被裝飾的函式名
def global_func(): pass

global_func() #相當於呼叫了內層函式inner

 

四,裝飾器進階

  1.裝飾帶引數的函式

# 裝飾帶引數的函式


def wrapper(func):
    def inner(*args, **kwargs):  # 實際執行函式的引數
        print('開始')
        r = func(*args, **kwargs)
        print(r)
        print('結束')
        return r
    return inner


@wrapper
def my_sum(x, y):
    print('我是my_sum函式')
    return x + y


ret = my_sum(10, 20)  # inner(10, 20)
print(ret)

 

  2.裝飾帶返回值的函式

# 裝飾帶返回值的函式
def wrapper(func):
    def inner():
        print('開始')
        r = func()  # 拿到原來函式的返回值
        print('結束')
        return r
    return inner


@wrapper
def f1():
    print('我是f1')
    return 100


ret = f1() #實際上是執行了inner內層函式,如果inner內層沒用renturn返回值,則f1也沒用返回值

 

  3.帶引數的裝飾器  *****

def mougehanshu(arg):
    def wrapper(func):
        def inner(*args, **kwargs):
            print('歡迎VIP使用者進入{}專欄!'.format(arg))
            func(*args, **kwargs)
        return inner
    return wrapper

# wrapper = mougehanshu()
#@mougehans(引數) 相當於 @wrapper


@mougehanshu('電影')  # 相當於mougehanshu()執行後返回wrapper
def movie():
    print('這是電影專欄!')


@mougehanshu('體育')  # @wrapper
def sport():
    print('這是體育專欄!')

 

  4.多個裝飾器裝飾同一個函式  *****

def foo1(func):
    print("d1")

    def inner1():
        print("inner1")
        return "<i>{}</i>".format(func())

    return inner1


def foo2(func):
    print("d2")

    def inner2():
        print("inner2")
        return "<b>{}</b>".format(func())

    return inner2


@foo1   #f1 = foo1(foo2(f1))=foo1(inner2,列印d2) = inner1 列印'd1'
@foo2   #執行foo2(f1) =inner2 列印'd2'
def f1():
    return "我是f1"

ret = f1()
print(ret)

# f1 = foo2(f1)    --> inner2
# f1 = foo1(inner2)  --> inner1
↓↓
#執行流程分析:
#f1()  ==  inner1()->列印'inner1'->return "<i>{}</i>".format(inner2())
#inner2() -> 列印'inner2'->return "<b>{}</b>".format(f1())
#f1() -> return "我是f1"
↓↓
print(ret) ---> '<i><b>我是f1</b></i>'

 

  5.裝飾器修復技術  ****

# 裝飾器修復技術
from functools import wraps

# Flask框架的時候用得上


def wrapper(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print('這是新功能')
        func(*args, **kwargs)
    return inner


@wrapper
def f1(arg1, arg2):
    """
    這裡寫這個函式是做什麼的
    :param arg1: 這個引數是什麼型別的
    :param arg2: 這個引數是什麼型別
    :return: None
    """
    print('嘿嘿嘿')


print(f1.__doc__)  
print(f1.__name__)
#若不修復的話,f1實際是指向inner的記憶體空間,
#f1.__doc__ 相當於 inner.__doc__中的內容
#f1.__name__ 相當於 inner.__name__中的內容

 

五,裝飾器究極進階

  1.類裝飾器

  2.裝飾類