python閉包——有狀態信息的函數

1.一等函數

在Python中,函數是一等公民(first class citizen)。
函數像其他類型的數據一樣,可以作爲參數傳入另一個函數,函數也可以作爲另一個函數的返回值。
函數定義語句和普通的賦值語句沒有區別,創建一個對象並用一個名字引用之。因此函數定義語句可以出現在任何賦值語句可以存在的地方,包括在另一個函數中。這就支持了嵌套函數的存在,在一個函數中定義另一個函數,二者分別稱爲外函數和內函數。這種範式可簡單稱爲嵌套函數模型。

2.閉包

閉包是嵌套函數模型中的一個重要應用。外函數把內函數作爲返回值返回,並且內函數中使用了外函數的局部變量,這樣的情況下被返回的內函數被稱爲閉包(closure),外函數稱爲工廠函數(factory function)。

def outer(k):
    def inner(n):
        return k ** n
    return inner

f = outer(2)
g = outer(3)
print(*map(f, (1, 2, 3)))
print(g(2))

Result:
2 4 8
9

由此例可以看出,調用outer將創建並返回inner,inner“記憶”了outer中的局部變量k的值。通過向outer傳遞不同的參數k,將得到保存了不同的參數k的相互獨立的函數對象,即帶有狀態的函數。

3.把數據和操作封裝在一起

閉包原本是數學中的概念,代表一個封閉區間。在Python中,閉包意指保存有狀態信息(即一組變量)的函數。且狀態信息無法通過外部訪問。
從某種意義上看,閉包和類一樣也是一種將數據和操作進行打包的方式,對於簡單的任務,可以使用閉包替代類的方式去實現。

def outer(state):
    def inner(cmd, value=0):
        nonlocal state
        if cmd == 'get':
            return state
        elif cmd == 'set':
            state = value
        elif cmd = 'add':
            state += value
        else:
            print('no such command {}!'.format(cmd))
    return inner

closure = outer(12)
print(closure('get'))
closure('set', 20)
print(closure('get'))
closure('add', 80)
f('decrese')

Result:
12
20
100
no such command decrease!

使用類的等價實現

class A:
    def __init__(self, state):
        self.state = state
    def getter(self):
        return self.state
    def setter(self, value):
        self.state = value
    def add(self.value):
        self.state += value

f = A(12)
f.getter()		#result: 12
f.setter(20)
f.getter()		#result: 20
f.add(80)
f.getter()		#result: 100

閉包和類一樣,是一種將數據(狀態信息,or environment)和操作進行打包的方法。
閉包是由工廠函數創建的,閉包的屬性由工廠函數定義,工廠函數就是閉包的模板,使用不用的參數可以創建不同的閉包,這也是工廠函數名字的由來。和類非常類似,類是對象的模板,使用類可以創造不同的對象。對象擁有相同的屬性和方法。
但是閉包和類不用的地方主要是閉包只能將一個函數和若干數據打包,而類可以將數據和任意多個方法打包在一起。這是類更強大的地方。另外,閉包的數據是完全私有的,外部不可訪問,而類沒有真正的私有屬性。

4.使用函數屬性保存數據

使用函數屬性同樣可以使函數和數據結合在一起,其作用和閉包非常相似,唯一的不同在於,函數屬性是外部可見的。

def outer(k):
    def inner(n):
        return inner.k ** n
    inner.k = k
    return inner

f = outer(2)
print(*map(f, (1, 2, 3)))
print(f.k)

Result:
2 4 8
2

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