0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

用最簡單的語言解釋Python的閉包是什么?

馬哥Linux運維 ? 來源:YXQ ? 2019-03-21 16:33 ? 次閱讀

Python中的閉包不是一個一說就能明白的概念,但是隨著你往學習的深入,無論如何你都需要去了解這么一個東西。

閉包的概念

我們嘗試從概念上去理解一下閉包。

在一些語言中,在函數中可以(嵌套)定義另一個函數時,如果內部的函數引用了外部的函數的變量,則可能產生閉包。閉包可以用來在一個函數與一組“私有”變量之間創(chuàng)建關聯關系。在給定函數被多次調用的過程中,這些私有變量能夠保持其持久性?!?維基百科

用比較容易懂的人話說,就是當某個函數被當成對象返回時,夾帶了外部變量,就形成了一個閉包??蠢?。

def make_printer(msg):  def printer():    print msg # 夾帶私貨(外部變量)  return printer # 返回的是函數,帶私貨的函數printer = make_printer('Foo!')printer()

支持將函數當成對象使用的編程語言,一般都支持閉包。比如Python, JavaScript。

如何理解閉包

閉包存在有什么意義呢?為什么需要閉包?

我個人認為,閉包存在的意義就是它夾帶了外部變量(私貨),如果它不夾帶私貨,它和普通的函數就沒有任何區(qū)別。同一個的函數夾帶了不同的私貨,就實現了不同的功能。其實你也可以這么理解,閉包和面向接口編程的概念很像,可以把閉包理解成輕量級的接口封裝。

接口定義了一套對方法簽名的約束規(guī)則。

def tag(tag_name):  def add_tag(content):    return "<{0}>{1}".format(tag_name, content)  return add_tag  content = 'Hello'add_tag = tag('a')print add_tag(content)# Helloadd_tag = tag('b')print add_tag(content)# Hello

在這個例子里,我們想要一個給content加tag的功能,但是具體的tag_name是什么樣子的要根據實際需求來定,對外部調用的接口已經確定,就是add_tag(content)。如果按照面向接口方式實現,我們會先把add_tag寫成接口,指定其參數和返回類型,然后分別去實現a和b的add_tag。

但是在閉包的概念中,add_tag就是一個函數,它需要tag_name和content兩個參數,只不過tag_name這個參數是打包帶走的。所以一開始時就可以告訴我怎么打包,然后帶走就行。

上面的例子不太生動,其實在我們生活和工作中,閉包的概念也很常見。比如說手機撥號,你只關心電話打給誰,而不會去糾結每個品牌的手機是怎么實現的,用到了哪些模塊。再比如去餐館吃飯,你只要付錢就可以享受到服務,你并不知道那桌飯菜用了多少地溝油。這些都可以看成閉包,返回來的是一些功能或者服務(打電話,用餐),但是這些功能使用了外部變量(天線,地溝油等等)。

你也可以把一個類實例看成閉包,當你在構造這個類時,使用了不同的參數,這些參數就是閉包里的包,這個類對外提供的方法就是閉包的功能。但是類遠遠大于閉包,因為閉包只是一個可以執(zhí)行的函數,但是類實例則有可能提供很多方法。

何時使用閉包

其實閉包在Python中很常見,只不過你沒特別注意這就是一個閉包。比如Python中的裝飾器Decorator,假如你需要寫一個帶參數的裝飾器,那么一般都會生成閉包。

為什么?因為Python的裝飾器是一個固定的函數接口。它要求你的裝飾器函數(或裝飾器類)必須返回這樣一種接口,接受一個函數并返回一個函數:

# how to definedef wrapper(func1): # 必須接受一個且僅一個函數作為參數  return func2 # 返回一個且僅一個callable對象,一般為函數# how to usedef target_func(args): # 目標函數  pass# 調用方式一,直接包裹result = wrapper(target_func)(args)# 調用方式二,使用@語法,等同于方式一@wrapperdef target_func(args):  passresult = target_func()

那么如果你的裝飾器如果帶參數呢?那么你就需要在原來的裝飾器上再包一層,用于接收這些參數。這些參數(私貨)傳遞到內層的裝飾器里后,閉包就形成了。所以說當你的裝飾器需要自定義參數時,一般都會形成閉包。(類裝飾器例外)

def html_tags(tag_name):  def wrapper_(func):    def wrapper(*args, **kwargs):      content = func(*args, **kwargs)      return "<{tag}>{content}".format(tag=tag_name, content=content)    return wrapper  return wrapper_@html_tags('b')def hello(name='Toby'):  return 'Hello {}!'.format(name)# 不用@的寫法如下# hello = html_tag('b')(hello)# html_tag('b') 是一個閉包,它接受一個函數,并返回一個函數print hello() # Hello Toby!print hello('world') # Hello world!

再深入一點

其實也不必太深入,理解這上面的概念,很多看起來頭疼的代碼也不過如此。

下面讓我們來了解一下閉包的包到底長什么樣子。其實閉包函數相對與普通函數會多出一個__closure__的屬性,里面定義了一個元組用于存放所有的cell對象,每個cell對象一一保存了這個閉包中所有的外部變量。

>>> def make_printer(msg1, msg2):  def printer():    print msg1, msg2  return printer>>> printer = make_printer('Foo', 'Bar') # 形成閉包>>> printer.__closure__  # 返回cell元組(, )>>> printer.__closure__[0].cell_contents # 第一個外部變量'Foo'>>> printer.__closure__[1].cell_contents # 第二個外部變量'Bar'

原理就是這么簡單。

參考鏈接

https://www.the5fire.com/closure-in-python.html

http://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • python
    +關注

    關注

    54

    文章

    4756

    瀏覽量

    84284
  • 閉包
    +關注

    關注

    0

    文章

    4

    瀏覽量

    2046

原文標題:用最簡單的語言解釋Python的閉包是什么?

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Python語言基礎2

    電子發(fā)燒友網站提供《Python語言基礎2.rar》資料免費下載
    發(fā)表于 07-17 17:23 ?1次下載

    python運行環(huán)境的安裝和配置

    Python是一種非常流行的編程語言,廣泛應用于科學計算、Web開發(fā)、人工智能等領域。為了能夠正常運行Python程序,我們需要先安裝和配置Python運行環(huán)境。本文將為您詳盡介紹
    的頭像 發(fā)表于 11-29 16:17 ?1038次閱讀

    Python運行環(huán)境有哪些

    ,也是最常用的解釋器。它是C語言編寫的,支持C的擴展和嵌入。CPython可以在各個操作系統(tǒng)上運行,并提供了Python的核心功能。 JPython: JPython是
    的頭像 發(fā)表于 11-29 16:14 ?1775次閱讀

    查看python安裝路徑的方法

    Python是一種高級編程語言,常用于開發(fā)Web應用、數據分析、人工智能等領域。在使用Python進行開發(fā)之前,我們需要先安裝Python解釋
    的頭像 發(fā)表于 11-29 14:54 ?1.1w次閱讀

    python shell怎么

    Python Shell是一種交互式解釋器,可以通過命令行直接運行Python代碼。在Shell中,可以輸入一行代碼并立即得到結果,非常適合于測試、嘗試新代碼或進行簡單的任務。本文將詳
    的頭像 發(fā)表于 11-29 14:36 ?1021次閱讀

    python語言特點有哪些

    Python是一種高級編程語言,由Guido van Rossum于1991年首次發(fā)布。它具有許多獨特的特點,這些特點使得Python在軟件開發(fā)領域變得非常流行。以下是關于Python
    的頭像 發(fā)表于 11-29 14:29 ?955次閱讀

    運行Python程序的幾種常見方法

    Python是一種高級編程語言,具有簡單易學,易于閱讀和調試的特點。當你完成了一個Python程序之后,你需要運行它以檢查程序是否按照預期工作。下面是運行
    的頭像 發(fā)表于 11-28 15:32 ?2136次閱讀

    如何運行Python程序

    運行Python程序非常簡單Python是一種解釋語言,這意味著可以直接通過解釋器來執(zhí)行代碼
    的頭像 發(fā)表于 11-24 09:31 ?1069次閱讀

    python嵌入和安裝程序的區(qū)別

    Python作為一種高級編程語言,擁有廣泛的應用領域和豐富的庫和框架支持。在使用Python開發(fā)項目時,我們通常會遇到需要依賴第三方庫或框架的情況,這時候就需要考慮如何將這些擴展功能包含到我們的項目
    的頭像 發(fā)表于 11-23 16:42 ?8393次閱讀

    Python編程語言屬于什么語言

    Python編程語言屬于高級編程語言中的一種。它是一種通用、面向對象、解釋型編程語言。Python
    的頭像 發(fā)表于 11-22 14:31 ?1266次閱讀

    Python自帶的命令窗口

    Python自帶的命令窗口,也稱為Python交互式解釋器,是Python編程語言的一個重要工具,它允許用戶在命令行界面中輸入和執(zhí)行
    的頭像 發(fā)表于 11-22 14:02 ?808次閱讀

    python怎樣運行代碼

    Python是一種廣泛使用的編程語言,用于開發(fā)各種類型的應用程序。它具有簡單易學的語法和強大的功能,可以用于編寫簡單的腳本、開發(fā)桌面應用、構建Web應用、進行科學計算等多種用途。在本文
    的頭像 發(fā)表于 11-22 10:31 ?1084次閱讀

    python簡單for循環(huán)例子

    Python是一種簡單而又強大的編程語言,通過其清晰的語法和豐富的功能庫,我們可以實現各種各樣的任務。其中一個最基本的語法結構就是for循環(huán),讓我們來看一下如何使用for循環(huán)來編寫一個最簡單
    的頭像 發(fā)表于 11-21 14:53 ?862次閱讀

    Go語言Python強多少

    1.都說Go語言性能非常強大,那么到底比Python強多少? 為了比較Go語言Python語言在單線程性能上的差距,我們可以做一個
    的頭像 發(fā)表于 11-02 14:05 ?481次閱讀
    Go<b class='flag-5'>語言</b>比<b class='flag-5'>Python</b>強多少

    Python SDK的使用

    Shodan Web端非常好用,但如果我們有從 Python 搜索的需求怎么辦? 沒關系,Shodan 官方也提供了 Python SDK ,下面就來講講這個 SDK 的使用。 1
    的頭像 發(fā)表于 10-30 15:51 ?693次閱讀
    <b class='flag-5'>Python</b> SDK<b class='flag-5'>包</b>的使用