[Python]閉包和裝飾器

1.閉包

從結構上說,必須是嵌套函數,內部函數必須用到外層函數的參數,外層函數的返回值必須是內層函數的引用。其次,本質上是數據和功能的結合。數據就是由外層函數提供,功能由內層函數實現,類似於定義了一個類。

def func(): #外部函數
    a = 1 #外部函數的作用域
    print("this is func.")
    def func(num): #內部函數
        print("this is func1.")
        print(num + a)
        return func1 #函數
    
#func()#運行外部函數,內部函數就被創建了
var = func() #創建過程在func函數的執行過程中
#var == func1
var(3)

this is func.
this is func1.
4


閉包內的閉包函數私有化了變量,完成了數據封裝,類似於面向對象。

mylist = [1,2,3,4,5]

def func(obj):
    print('func:', obj)
    def func1():
        obj[0] += 1
        print('func1:', obj)
    return func1
var = func(mylist)

var()
var()
var()

#var: obj   print('func1:', obj)

func: [1, 2, 3, 4, 5]
func1: [2, 2, 3, 4, 5]
func1: [3, 2, 3, 4, 5]
func1: [4, 2, 3, 4, 5]


用於裝飾器,又稱語法糖

2.裝飾器

@func1
def func():
print(‘aaa’)
不影響原有函數的功能,還能添加新的功能。(也就是已經實現功能的代碼,是封閉的不允許隨意改動,可以擴展開發,增加功能。)

def func1(func): #外部閉包函數的參數是被裝飾的函數對象
    def func2():
        print('aaabbb')
        return func() #返回了外部函數接收的被裝飾函數的調用
    return func2
        
#return func #返回了函數對象
#return func() #返回的是一個函數的調用

@func1
def myprint():
    print('你好,我是print')
    
myprint() #func1(myprint)() #接收被裝飾的函數作爲參數,而且還要繼續調用一次
#1. func1(myprint)() -> func2
#2. func2() -> print('aaabbb') -> return func() #裝飾器使得func() = myprint()
#3. return myprint()-> print('你好,我是print')

aaabbb
你好,我是print



def func1() : #外部閉包函數的參數是被裝飾的函數對象
    def func2():
        print('aaabbb')
        return func() #返回了外部函數接收的被裝飾函數的調用
    return func2
        
#return func #返回了函數對象
#return func() #返回的是一個函數的調用

@func1
def myprint():
    print('你好,我是print')
    
myprint()

TypeError: func1() takes 0 positional arguments but 1 was given


即,func1()中沒有參數,而且參數應爲函數。

裝飾器函數帶參數:多一層包裝來接收裝飾器的參數

def arg_func(sex):
    def func1(data):
        def func2():
            if sex == 'man':
                print('你不可以生娃')
            else:
                print('你可以生娃')
            return data()
        return func2
    return func1
    
#arg_func(sex='man')()() -> func1
#func1() -> func2
#func2() -> print('你不可以生娃') or print('你可以生娃')     data()
    
    
@arg_func(sex='man')    
def man():
    print('好好上班.')
    
@arg_func(sex='woman')      
def woman():
    print('好好上班.')
    
man()
woman()

你不可以生娃
好好上班.
你可以生娃
好好上班.


被裝飾的函數帶參數:只需要在最內部函數傳入參數即可。

def func1(func):  
    def func2(x,y):
        print(x,y)
        x += 5
        y += 5       
        return func(x, y)
    return func2

@func1
def mysum(a,b): # a = a + 5, b = b + 5
    print( a + b)
    
mysum(1,2)

1 2
13


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章