程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python知識:啥叫閉包(Closure)?

編輯:Python

一、Python之閉包(Closure)

        什麼是閉包呢?這裡借用《Fluent Python》中對閉包的定義 "a closure is function with an extended scope that encompasses non-global variables referenced in the body of the function but not defined there"。簡單來說:閉包=函數+自由變量的引用

        那麼什麼是自由變量(free variables)?在一個函數中,如果某個變量既不是在函數內部創建的也不屬於函數的形參,並且它也不是全局變量(global variables),那麼這個變量對該函數來說就是自由變量。說的太多不如給一個例子:

def outer():
var = 3
def inner():
print(var)
return inner
func = outer()
func() # print 3
var = 5
func() # print 3

        這段代碼中,函數inner和var就構成了閉包,var對於inner來說就是自由變量。可以看到var不是在inner中創建的,而是在outer中創建。那麼函數inner如何存儲變量var呢?答案就是inner.__code__.co_freevars和inner.__closure__,前者記錄了自由變量的名字,後者記錄了自由變量的值。

print func.__code__.co_freevars # ('var',)
print func.__closure__[0].cell_contents # 3

 二、工作機理

        閉包單元指的是函數所需的值,但取自周圍的范圍。

        當 Python 編譯嵌套函數時,它會記下它引用但僅在嵌套函數和父范圍的代碼對象中的父函數(不是全局變量)中定義的任何變量。這些分別是這些函數的 __code__ 對象上的 co_freevars 和 co_cellvars 屬性。

        然後,當您實際創建嵌套函數(執行父函數時發生)時,這些引用將用於將閉包附加到嵌套函數。

        函數閉包包含一個單元元組,每個單元對應一個自由變量(以 co_freevars 命名);單元格是對父作用域的局部變量的特殊引用,它遵循那些局部變量指向的值。最好用一個例子來說明這一點: 

def foo():
def bar():
print(spam)
spam = 'ham'
bar()
spam = 'eggs'
bar()
return bar
b = foo()
b()

        在上面的例子中,函數 bar 有一個閉包單元,它指向函數 foo 中的垃圾郵件。單元格遵循垃圾郵件的值。更重要的是,一旦 foo() 完成並返回 bar,即使 foo 中的變量 spam 不再存在,單元格仍會繼續引用該值(字符串雞蛋)。

因此,上面的代碼輸出: 

>>> b=foo()
ham
eggs
>>> b()
eggs

此時, b.__closure__[0].cell_contents是 'eggs'

請注意,調用 bar() 時會取消引用閉包;閉包並沒有捕捉到這裡的價值。當您生成引用循環變量的嵌套函數(使用 lambda 表達式或 def 語句)時,這會有所不同:

def foo():
bar = []
for spam in ('ham', 'eggs', 'salad'):
bar.append(lambda: spam)
return bar
for bar in foo():
print bar()

        上面的他將連續打印 3 次沙拉,因為所有三個 lambda 函數都引用 spam 變量,而不是創建函數對象時綁定的值。當 for 循環結束時,垃圾郵件被綁定到“沙拉”,因此所有三個閉包都將解析為該值。

>>>python.__closure__
(<cell at 0x67f50: str object at 0x69230>,)
>>>python.__closure__[0].cell_contents

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved