鍍金池/ 教程/ Python/ Python閉包
Python異常處理
Python循環(huán)
Python基本運(yùn)算符
Python網(wǎng)絡(luò)編程(Sockets)
Python可以開發(fā)哪些程序?
Python XML解析和處理
Python數(shù)字
Python函數(shù)
Python變量類型
Python os模塊方法
Python迭代器
Python安裝和環(huán)境配置
Python構(gòu)造函數(shù)
Python文件對(duì)象方法
Python日期和時(shí)間
Python的歷史
Python生成器
Python+MySQL數(shù)據(jù)庫操作(PyMySQL)
Python命令行參數(shù)
Python元組
Python發(fā)送郵件
Python列表
Python文件讀寫
Python教程
Python面向?qū)ο螅惡蛯?duì)象)
Python多線程編程
Python多重繼承
Python決策
Python是什么?
Python快速入門
Python繼承
Python字典
Python字符串
Python操作符重載
Python正則表達(dá)式
Python閉包
Python修飾器
Python功能特點(diǎn)
Python模塊

Python閉包

在本文中,您將了解什么是Python閉包,如何定義閉包以及應(yīng)該如何使用閉包。

嵌套函數(shù)中的非局部變量

在進(jìn)入閉包之前,我們必須先了解一個(gè)嵌套函數(shù)和非局部變量。

在函數(shù)中定義另一個(gè)函數(shù)稱為嵌套函數(shù)。嵌套函數(shù)可以訪問包圍范圍內(nèi)的變量。

在Python中,這些非局部變量只能在默認(rèn)情況下讀取,我們必須將它們顯式地聲明為非局部變量(使用nonlocal關(guān)鍵字)才能進(jìn)行修改。

以下是訪問非局部變量的嵌套函數(shù)的示例。

def print_msg(msg):
# This is the outer enclosing function

    def printer():
# This is the nested function
        print(msg)

    printer()

# We execute the function
# Output: Hello
print_msg("Hello")

可以看到嵌套函數(shù)printer()能夠訪問封閉函數(shù)的非局部變量msg。

定義閉包函數(shù)

在上面的例子中,如果函數(shù)print_msg()的最后一行返回printer()函數(shù)而不是調(diào)用它,會(huì)發(fā)生什么? 如該函數(shù)定義如下 -

def print_msg(msg):
# This is the outer enclosing function

    def printer():
# This is the nested function
        print(msg)

    return printer  # this got changed

# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()

這樣是不尋常的。

print_msg()函數(shù)使用字符串“Hello”進(jìn)行調(diào)用,返回的函數(shù)被綁定到另一個(gè)名稱。 在調(diào)用another()時(shí),盡管我們已經(jīng)完成了print_msg()函數(shù)的執(zhí)行,但仍然記住了這個(gè)消息。

一些數(shù)據(jù)(“Hello”)附加到代碼中的這種技術(shù)在Python中稱為閉包。

即使變量超出范圍或函數(shù)本身從當(dāng)前命名空間中刪除,也會(huì)記住封閉范圍內(nèi)的值。

嘗試在Python shell中運(yùn)行以下內(nèi)容以查看輸出。

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

什么時(shí)候閉包?

從上面的例子可以看出,當(dāng)嵌套函數(shù)引用其封閉范圍內(nèi)的值時(shí),在Python中有使用了一個(gè)閉包。

在Python中創(chuàng)建閉包必須滿足的標(biāo)準(zhǔn)將在以下幾點(diǎn) -

  • 必須有一個(gè)嵌套函數(shù)(函數(shù)內(nèi)部的函數(shù))。
  • 嵌套函數(shù)必須引用封閉函數(shù)中定義的值。
  • 閉包函數(shù)必須返回嵌套函數(shù)。

何時(shí)使用閉包?

那么閉包是什么好的?

閉包可以避免使用全局值并提供某種形式的數(shù)據(jù)隱藏。它還可以提供面向?qū)ο蟮慕鉀Q問題的解決方案。

當(dāng)在類中幾乎沒有方法(大多數(shù)情況下是一種方法)時(shí),閉包可以提供一個(gè)替代的和更優(yōu)雅的解決方案。 但是當(dāng)屬性和方法的數(shù)量變大時(shí),更好地實(shí)現(xiàn)一個(gè)類。

這是一個(gè)簡(jiǎn)單的例子,其中閉包可能比定義類和創(chuàng)建對(duì)象更為優(yōu)先。

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier

# Multiplier of 3
times3 = make_multiplier_of(3)

# Multiplier of 5
times5 = make_multiplier_of(5)

# Output: 27
print(times3(9))

# Output: 15
print(times5(3))

# Output: 30
print(times5(times3(2)))

Python中的裝飾器也可以廣泛使用閉包。值得注意的是,可以找到封閉函數(shù)中包含的值。

所有函數(shù)對(duì)象都有一個(gè)__closure__屬性,如果它是一個(gè)閉包函數(shù),它返回一個(gè)單元格對(duì)象的元組。 參考上面的例子,我們知道times3times5是閉包函數(shù)。

>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

單元格(cell)對(duì)象具有存儲(chǔ)閉合值的屬性:cell_contents。

>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5

上一篇:Python快速入門下一篇:Python生成器