如何使用閉包方法

本篇內(nèi)容介紹了“如何使用閉包方法”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

我們注重客戶提出的每個(gè)要求,我們充分考慮每一個(gè)細(xì)節(jié),我們積極的做好成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)服務(wù),我們努力開拓更好的視野,通過不懈的努力,成都創(chuàng)新互聯(lián)公司贏得了業(yè)內(nèi)的良好聲譽(yù),這一切,也不斷的激勵(lì)著我們更好的服務(wù)客戶。 主要業(yè)務(wù):網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),重慶小程序開發(fā),網(wǎng)站開發(fā),技術(shù)開發(fā)實(shí)力,DIV+CSS,PHP及ASP,ASP.Net,SQL數(shù)據(jù)庫(kù)的技術(shù)開發(fā)工程師。

什么是 Python 閉包?

首先,讓我使用一個(gè)簡(jiǎn)單的示例來說明什么是 Python 中的閉包??聪旅娴暮瘮?shù):

def outer():     x = 1     def inner():         print(f'x in outer function: {x}')     return inner

在一個(gè)函數(shù)內(nèi)部定義另外一個(gè)函數(shù),并返回這個(gè)函數(shù),這種特性就是閉包。檢查 outer 函數(shù)的返回值,可以確認(rèn)這是一個(gè)函數(shù)。

>>> def outer(): ...     x = 1 ...     def inner(): ...         print(f'x in outer function: {x}') ...     return inner ... >>> outer <function outer at 0x7fb2ecdac9d0> >>> outer() <function outer.<locals>.inner at 0x7fb2ecdaca60> >>>

閉包這種特性能做什么呢?因?yàn)楹瘮?shù)返回的是一個(gè)函數(shù),我們就可以調(diào)用這個(gè)函數(shù),比如:

>>> outer()() x in outer function: 1 >>>

不過我們一般會(huì)這么使用閉包,這樣太丑陋了。你可能會(huì)好奇這個(gè)跟遞歸有什么關(guān)系?別著急,讓我們慢慢體會(huì)閉包的牛逼之處。

閉包內(nèi)的變量訪問

從前述的運(yùn)行結(jié)果來看,inner 函數(shù)可以訪問 outer 函數(shù)內(nèi)部定義的變量 x,但是卻無法修改它,下面的代碼運(yùn)行時(shí)會(huì)報(bào)錯(cuò):

>>> def outer(): ...     x = 1 ...     def inner(): ...         print(f'x in outer function (before modifying): {x}') ...         x += 1 ...         print(f'x in outer function (after modifying): {x}') ...     return inner ... >>> f = outer() >>> f() Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "<stdin>", line 4, in inner UnboundLocalError: local variable 'x' referenced before assignment >>>

為了解決這個(gè)問題,我們可以加上 nonlocal 關(guān)鍵字,告訴 inner 函數(shù),這不是一個(gè)本地變量:

>>> def outer(): ...     x = 1 ...     def inner(): ...         nonlocal x ...         print(f'x in outer function (before modifying): {x}') ...         x += 1 ...         print(f'x in outer function (after modifying): {x}') ...     return inner ... >>> >>> f = outer() >>> f() x in outer function (before modifying): 1 x in outer function (after modifying): 2 >>> f() x in outer function (before modifying): 2 x in outer function (after modifying): 3 >>> f() x in outer function (before modifying): 3 x in outer function (after modifying): 4 >>>

有沒有發(fā)現(xiàn),x 的值竟然被保存了下來,每次調(diào)用一下,就增加了 1,這就是閉包的妙處。

用閉包來替換遞歸

利用上述閉包會(huì)保留調(diào)用結(jié)果的特性,我們可以用這個(gè)來替換遞歸,比如利用閉包計(jì)算斐波那契數(shù)列:

def fib():     x1 = 0     x2 = 1     def get_next_number():         nonlocal x1, x2         x3 = x1 + x2         x1, x2 = x2, x3         return x3     return get_next_number

可以這樣調(diào)用來生產(chǎn)斐波那契數(shù)列:

>>> def fib(): ...     x1 = 0 ...     x2 = 1 ...     def get_next_number(): ...         nonlocal x1, x2 ...         x3 = x1 + x2 ...         x1, x2 = x2, x3 ...         return x3 ...     return get_next_number ... >>> fibonacci = fib() >>> for i in range(2, 21): ...     num = fibonacci() ...     print(f'The {i}th Fibonacci number is {num}') ... The 2th Fibonacci number is 1 The 3th Fibonacci number is 2 The 4th Fibonacci number is 3 The 5th Fibonacci number is 5 The 6th Fibonacci number is 8 The 7th Fibonacci number is 13 The 8th Fibonacci number is 21 The 9th Fibonacci number is 34 The 10th Fibonacci number is 55 The 11th Fibonacci number is 89 The 12th Fibonacci number is 144 The 13th Fibonacci number is 233 The 14th Fibonacci number is 377 The 15th Fibonacci number is 610 The 16th Fibonacci number is 987 The 17th Fibonacci number is 1597 The 18th Fibonacci number is 2584 The 19th Fibonacci number is 4181 The 20th Fibonacci number is 6765 >>>

而使用遞歸方法計(jì)算斐波那契數(shù)列的方法如下所示:

def fib_recursion(n:int) -> int:     if n <= 1:         return n     return fib_recursion(n-1) + fib_recursion(n-2)

把之前的閉包版本封裝一下:

def fib():     x1 = 0     x2 = 1     def get_next_number():         nonlocal x1, x2         x3 = x1 + x2         x1, x2 = x2, x3         return x3     return get_next_number  def fib_closure(n):     f = fib()     for i in range(2, n+1):         num = f()     return num

這樣使用 fib_closure(20) 就可以計(jì)算出結(jié)果:

In [4]: fib_closure(20) Out[4]: 6765  In [5]: fib_recursion(20) Out[5]: 6765  In [6]:

現(xiàn)在使用 IPython 來測(cè)試下這兩者的性能:

In [6]: %time fib_closure(20) CPU times: user 10 &micro;s, sys: 1e+03 ns, total: 11 &micro;s Wall time: 14.1 &micro;s Out[6]: 6765  In [7]: %time fib_recursion(20) CPU times: user 2.76 ms, sys: 15 &micro;s, total: 2.78 ms Wall time: 2.8 ms Out[7]: 6765

可以看出兩差相差近 1000 倍,這還只是計(jì)算到第 20 個(gè)數(shù)的情況下,如果計(jì)算到 100,那使用遞歸會(huì)計(jì)算很久甚至無法計(jì)算出來。

閉包的其他用處

Python 的閉包不僅僅用于替換遞歸,還有很多場(chǎng)景可以使用閉包。比如學(xué)生成績(jī)的分類函數(shù):

學(xué)生成績(jī)數(shù)據(jù):

students = {     'Alice': 98,     'Bob': 67,     'Chris': 85,     'David': 75,     'Ella': 54,     'Fiona': 35,     'Grace': 69 }

現(xiàn)在需要根據(jù)學(xué)生成績(jī)進(jìn)行分類,通常情況下我們會(huì)寫多個(gè)函數(shù)來進(jìn)行分類,而分類的標(biāo)準(zhǔn)又會(huì)經(jīng)常變化,這時(shí)候閉包就很方便了:

def make_student_classifier(lower_bound, upper_bound):     def classify_student(exam_dict):         return {k:v for (k,v) in exam_dict.items() if lower_bound <= v < upper_bound}     return classify_student  grade_A = make_student_classifier(80, 100) grade_B = make_student_classifier(70, 80) grade_C = make_student_classifier(50, 70) grade_D = make_student_classifier(0, 50)

如果分類標(biāo)準(zhǔn)變化,直接個(gè)性函數(shù)的參數(shù)即可,主要代碼邏輯不變,如果想查找成績(jī)分類為 A 的學(xué)生,只需要調(diào)用 grade_A(students)  即可:

In [13]: grade_A(students) Out[13]: {'Alice': 98, 'Chris': 85}

閉包使用上述分類函數(shù)很容易修改且更加易讀。

“如何使用閉包方法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

名稱欄目:如何使用閉包方法
網(wǎng)站地址:http://muchs.cn/article10/iehpgo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、網(wǎng)站內(nèi)鏈、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站收錄、動(dòng)態(tài)網(wǎng)站外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司