1. 程式人生 > 其它 >python函式閉包

python函式閉包

閉包函式

在一些語言中,在函式中可以(巢狀)定義另一個函式時,如果內部的函式引用了外部的函式的變數,則可能產生閉包。閉包可以用來在一個函式與一組“私有”變數之間建立關聯關係。在給定函式被多次呼叫的過程中,這些私有變數能夠保持其永續性。——維基百科

閉包函式的條件

  • 閉包函式必須有內嵌函式
  • 閉包函式必須引用外層函式的變數
  • 閉包函式返回內嵌函式的地址(函式名稱)

閉包函式示例

def first():
    age = 10

    def second():  # 內嵌函式
        print(age)  # 引用外層函式的變數

    return second  # 返回內嵌函式的函式名

我們稱上述函式second為一個閉包函式

判斷一個函式是否為閉包

我們可以通過函式名.closure 在函式為閉包時,返回一個cell ,如果不是閉包函式則返回None

def first():
    age = 10

    def second():  # 內嵌函式
        print(age)  # 引用外層函式的變數
    print(second.__closure__)

    return second  # 返回內嵌函式的函式名

>>> s = first()
>>> s()
(<cell at 0x0000027BBE7A7318: int object at 0x00007FF9120FFB60>,)
100
def first():
    age = 10

    def second():  # 內嵌函式
        print(10)  # 引用外層函式的變數
    print(second.__closure__)

    return second  # 返回內嵌函式的函式名

>>> s = first()
>>> s()
None
10

second不是閉包函式,因為沒有引用外層函式的變數

def first(age):
    def second():  # 內嵌函式
        print(age)  # 引用外層函式的變數
    print(second.__closure__)

    return second  # 返回內嵌函式的函式名

>>> s = first()
>>> s()
(<cell at 0x0000016A608D6408: int object at 0x00007FF9120FFB60>,)
100

second是閉包函式,引用了外層函式的引數

閉包函式的作用

開篇說到閉包函式被多次呼叫的過程中,其引用的外層變數能夠保持其永續性,我們以一個例項來理解這一點。
假如有一個名為avg的函式,它的作用是計算不斷增加的系列值的均值;例如,整個歷史中某個商品的平均收盤價。每天都會增加新的價格,因此平均值要考慮目前為止所有的價格。

實現方式一

class Averager():

    def __init__(self):
        self.series = []

    def __call__(self, new_val):
        self.series.append(new_val)
        total = sum(self.series)

        return total / len(self.series)

>>> avg = Averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0

實現方式二

def make_averager():
    series = []
    
    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total / len(series)
    
    return averager


>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0