bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

python閉包函數 python 閉包函數

Python嵌套函數和閉包

在Python語言中,可以在函數中定義函數。 這種在函數中嵌套定義的函數也叫內部函數。我們來看下面的代碼:

創新互聯建站服務項目包括永德網站建設、永德網站制作、永德網頁制作以及永德網絡營銷策劃等。多年來,我們專注于互聯網行業,利用自身積累的技術優勢、行業經驗、深度合作伙伴關系等,向廣大中小型企業、政府機構等提供互聯網行業的解決方案,永德網站推廣取得了明顯的社會效益與經濟效益。目前,我們服務的客戶以成都為中心已經輻射到永德省份的部分城市,未來相信會繼續擴大服務區域并繼續獲得客戶的支持與信任!

上述代碼中,定義了函數greet,在函數greet內部又定義了一個函數inner_func, 并調用該函數打印了一串字符。

我們可以看到,內部函數inner_func的定義和使用與普通函數基本相同。需要注意的是變量的作用域,在上述代碼中,函數參數name對于全局函數greet是局部變量,對內部函數inner_func來說則是非局部變量。內部函數對于非局部變量的訪問規則類似于標準的外部函數訪問全局變量。

從這個例子我們還可以看到內部函數的一個作用,就是通過定義內部函數的方式將一些功能隱藏起來,防止外部直接調用。常見的場景是,在一個復雜邏輯的函數中,將一些小的任務定義成內部函數,然后由這個外層函數使用,這樣可以使代碼更為清晰,易于維護。這些內部函數只會在這個外層函數中使用,不能被其他函數或模塊使用。

在Python語言中, 函數也是對象,它可以被創建、賦值給變量,或者作為函數的返回值。我們來看下面這個例子。

在上述代碼中,在函數gen_greet內部定義了inner_func函數,并返回了一個inner_func函數對象。外部函數gen_greet返回了一個函數對象,所以像gen_greet這樣的函數也叫工廠函數。

在內部函數inner_func中,使用了外部函數的傳參greet_words(非局部變量),以及函數的參數name(局部變量),來打印一個字符串。

接下來,調用gen_greet("Hello")創建一個函數對象say_hello,緊接著調用say_hello("Mr. Zhang"),輸出的結果為:Hello, Mr. Zhang!

同樣的,調用gen_greet("Hi")創建一個函數對象say_hi,調用say_hello("Mr. Zhang"),輸出的結果為:Hi,Tony!

我們可以發現,gen_greet返回的函數對象具有記憶功能,它能夠把所需使用的非局部變量保存下來,用于后續被調用的時候使用。這種保存了非局部變量的函數對象被稱作閉包(closure)。

那么閉包是如何實現的呢?其實并不復雜,函數對象中有一個屬性__closure__,它就是在創建函數對象時用來保存這些非局部變量的。

__closure__屬性是一個元組或者None類型。在上述代碼中,我們可以通過下面方式查看:

函數的嵌套所實現的功能大都可以通過定義類的方式來實現,而且類是更加面向對象的代碼編寫方式。

嵌套函數的一個主要用途是實現函數的裝飾器。我們看下面的代碼:

在上述代碼中,logger函數返回函數with_logging,with_logging則是打印了函數func的名稱及傳入的參數,然后調用func, 并將參數傳遞給func。其中的@wraps(func)語句用于復制函數func的名稱、注釋文檔、參數列表等等,使得with_logging函數具有被裝飾的函數func相同的屬性。

代碼中接下來用@logger對函數power_func進行修飾,它的作用等同于下面的代碼:

可見,裝飾器@符其實就是上述代碼的精簡寫法。

通過了解了嵌套函數和閉包的工作原理,我們在使用過程中就能夠更加得心應手了。

python中使用閉包及修改外部函數的局部變量

在python中,函數可以被嵌套定義,也就是說,函數中可以定義函數。該函數還可以將其內部定義的函數作為返回值返回。

閉包的定義:一般來說,我們可以認為,如果一個函數可以讀取其他函數中的局部變量,那么它們就構成了閉包。

注意 :閉包的定義不是特別清晰,但大體上的意思是這樣的。

我們知道,普通的函數是可以使用全局變量的

類似的,函數中定義的函數,也是可以使用外部函數的變量的。因此,滿足了函數讀取了其他函數局部變量的這一條件,他們因此構成了閉包。

在閉包的使用中,我們可以先給外部的函數賦予不同的局部變量,然后再調用其中內部的函數時,就可以讀取到這些不同的局部變量了。

外部變量的使用 在普通函數中,雖然可以直接使用全局變量,但是不可以直接修改全局變量。從變量的作用域來說,一旦你嘗試修改全局變量,那么就會嘗試創建并使用一個同名的局部變量。因此,如果你需要在普通函數中修改全局變量,需要使用global

同樣的,如果你希望通過定義在內部的函數去修改其外部函數的變量,那么必須使用nonlocal

閉包與自由變量

之前 分析了裝飾器的語法,由此可以直接推導出其基本框架。但為了寫出一個功能完整的裝飾器,還需要了解一個概念——閉包。

閉包(closure) ,是引用了自由變量的函數。 這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。

看下面的例子

對 f 內部的函數 g 來說,參數 a 既不是它的參數,也不是它的局部變量,而是它的自由變量。該自由變量可以

閉包和嵌套函數的概念有所區別。閉包當然是嵌套函數,但沒有引用自由變量的嵌套函數卻不是閉包。

Python 的函數有一個只讀屬性 __closure__ ,存儲的就是函數所引用的自由變量,

如果僅僅是嵌套函數,它的 __closure__ 應該是 None 。

閉包有個重要的特性:內部函數只能引用而不能修改外部函數中定義的自由變量。試圖直接修改只有兩種結果,要么運行出錯,要么你以為你修改了,實際并沒有。

不能修改不是因為 Python 設計者故意限制,不給它權限,而是外部的自由變量被內部的局部變量覆蓋了;被覆蓋了也不是閉包獨有的特性,從普通函數內部同樣也不能直接修改全局變量。Python 命名空間的查找規則簡寫為 LEGB,四個字母分別代表 local、enclosed、global 和 build-in,閉包外層函數的命名空間就是 enclosed。Python 在檢索變量時,按照 L - E - G - B 的順序依次查找,如果在 L 中找到了變量,就不會繼續向后查找。

在示例 1 中,你的本意是修改自由變量 number ,然而并不能:由于存在對 number 的賦值語句( number += 1 ),Python 會認為 number 是 printer 的局部變量,可是在局部變量字典中又查找不到它的定義,只好拋出異常。拋出的異常不是因為不能修改自由變量,而是局部變量還沒賦值就被引用了。

在示例 2 中,Python 成功地在 printer 內定義了局部變量 number ,并覆蓋了同名自由變量,你可能以為自己成功修改了 print_msg 中的 number ,然而并沒有。

怎么才能修改呢?

一種做法是利用可變類型(mutable)的特性,把變量存放在列表(List)之中。對可變的列表的修改并不需要對列表本身賦值, number[0] = 3 只是修改了列表元素。雖然列表發生了變化,但引用列表的變量卻并沒有改變,巧妙地“瞞”過了 Python。見示例3。

Python 3 引入了 nonlocal 關鍵字,明確告訴解釋器:這不是局部變量,要找上外頭找去。在示例 4 中, nonlocal 幫助我們實現了所期望的對自由變量的修改。

其實,在 Python 2 中,用 global 代替 nonlocal ,也能達到類似的效果,但由于全局變量的不易控制,這種做法不被提倡。

下面的例子很好地展示了自由變量的特點:與引用它的函數一同存在,而想要修改它,得小心謹慎。

裝飾器 rate_limit 的作用,是限制被裝飾的函數每秒內最多被訪問 max_per_sec 次。為此,需要維護一個變量用以記錄上次被調用的時刻,它獨立于函數之外,和被修飾的函數一同存在,還能在每次被調用的時候更新。 last_time_called 就是這樣的變量。為了正確地更新, last_time_called 以列表的形式存在。如果在 Python 3 中,它也可以直接存為 float ,只要在內部函數中聲明為 nonlocal ,也可以達到同樣的目的。

求幫助,Python閉包和返回函數問題

(1)unpack tuple和list, 可以讓函數返回多個值

def count():

return (1, 2, 3) # 或者 return [1, 2, 3]

# 把列表解包,把1 2 3 分別賦值給 a b c

a, b, c = count()

print a, b, c

# 輸出 1, 2, 3

(2)假設你知道Python的dict類型。Python中,在函數中定義一個變量的時候,會在一個隱藏的叫locals的dict里面插入key-value,其中key是變量名,value是變量值。而引用一個變量的時候,則首先會在這個叫locals的dict里面,根據變量名作為key,去查對應的值。

var = 1 # 你可以認為這里進行了 locals['var'] = 1 的操作

print var # 在對var變量進行求值的時候,就在locals['var']里面找var變量對應的值

(3)for循環中,每次循環只是給 `i` 重新綁定值

for i in (1, 2, 3):

print i

print i

# 一次輸入 1 2 3 3

每次`for i in (1, 2, 3)`相當于在`print i`之前,進行了

`locals['i'] = 1`

`locals['i'] = 2`

`locals['i'] = 3`

的操作

所以最后的`print i`再去locals字典里面找`i`的時候,就變成 3 了。

(4)閉包是 一個函數加上這個函數引用的外部變量

var = 1

def f():

print var

# 這里的閉包是函數 f 和 f 引用的外部變量 var

def count():

var2 = 2

def f():

print var2

# 這里的閉包是函數 f 和 f 引用的外部變量 var2

return f

拿第一個函數 f 來說。在 f 運行的時候,解釋器拿著'var'這個字符串去locals字典里面找,發現找不到,于是在closure字典里面找,最后closure字典里面找,你可以認為就是找closure['var'],然后發現找到對應的值。count里面的 f 函數同理。

(為了容易理解,我這里說謊了。實際上 f 壓根沒有closure,count里面的 f 才有。其實closure壓根不是像locals那樣的字典)

(5)函數定義時,函數只是記錄變量的名字。

要區分什么是名字,什么是值。

`i = 1`這里 i 只是名字,只是一個字符串 'i' 。這句話運行完,locals['i'] = 1,就說 i 對應的值是1

def count():

fs = []

for i in range(1, 4):

# 定義一個函數,等價于運行了 locals['f'] = 真正生成的函數

# 每次循環,這里都會重新生成一個函數,然后把重新生成的函數賦值給 locals['f']

def f():

return i * i # 引用了'i'這個名字,但并不是引用了'i'對應的值

# 等價于 locals['fs'].append(locals['f'])

# f 不是函數,它只是一個名字'f'。f 引用的東西,也就是locals['f']才是真正的函數

fs.append(f)

# 于是這個for循環生成了三個函數,這三個函數是沒有名字的,這個函數運行完后,它們跟'f'這個名字就毛關系都沒有了(是的我說慌了,但可以先不管)

# 把整個列表返回,這個列表包含了三個函數

return fs

# count()返回三個函數的列表,unpack 列表的語法把列表中的三個函數抽出來,重新給他們命名為 f1, f2, f3

# 也就是說,

# locals['f1'] = 列表中的第1個函數

# locals['f2'] = 列表中的第2個函數

# locals['f3'] = 列表中的第3個函數

# 這三個函數跟'f'這個名字現在毛關系都沒有。(其實是有的,但為了說明需要簡化,現在你可以完全不管括號里面說的話)

f1, f2, f3 = count()

print f1(), f2(), f3()

# 好了我們運行它們,輸入都是 9

# def f():

# return i * i

這是因為 f1 現在對應的函數,里面引用了 'i' 這個字符串,我們根據 'i '這個字符串去找它對應的值,先找到 f 當前的locals字典,發現沒有,因為函數定義的時候沒有定義 i 變量。然后再去closure['i']里面找,因為Python是通過closure字典實現閉包的(就當它是對的好不好),所以我們可以在closure['i']找到值,這個值就是我們上一次運行的時候count函數里面殘留的locals['i'],而由于for循環三遍之后,locals['i'] == 3,所以找到 i 的值就是3。所以最后輸出都是9

新聞名稱:python閉包函數 python 閉包函數
URL網址:http://vcdvsql.cn/article22/doicicc.html

成都網站建設公司_創新互聯,為您提供網站導航網站設計公司動態網站標簽優化外貿網站建設品牌網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都定制網站網頁設計