重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
本篇內容介紹了“如何使用閉包方法”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
我們注重客戶提出的每個要求,我們充分考慮每一個細節,我們積極的做好成都做網站、成都網站設計服務,我們努力開拓更好的視野,通過不懈的努力,成都創新互聯公司贏得了業內的良好聲譽,這一切,也不斷的激勵著我們更好的服務客戶。 主要業務:網站建設,網站制作,網站設計,重慶小程序開發,網站開發,技術開發實力,DIV+CSS,PHP及ASP,ASP.Net,SQL數據庫的技術開發工程師。
什么是 Python 閉包?
首先,讓我使用一個簡單的示例來說明什么是 Python 中的閉包。看下面的函數:
def outer(): x = 1 def inner(): print(f'x in outer function: {x}') return inner
在一個函數內部定義另外一個函數,并返回這個函數,這種特性就是閉包。檢查 outer 函數的返回值,可以確認這是一個函數。
>>> def outer(): ... x = 1 ... def inner(): ... print(f'x in outer function: {x}') ... return inner ... >>> outer>>> outer() .inner at 0x7fb2ecdaca60> >>>
閉包這種特性能做什么呢?因為函數返回的是一個函數,我們就可以調用這個函數,比如:
>>> outer()() x in outer function: 1 >>>
不過我們一般會這么使用閉包,這樣太丑陋了。你可能會好奇這個跟遞歸有什么關系?別著急,讓我們慢慢體會閉包的牛逼之處。
閉包內的變量訪問
從前述的運行結果來看,inner 函數可以訪問 outer 函數內部定義的變量 x,但是卻無法修改它,下面的代碼運行時會報錯:
>>> 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 "", line 1, in File " ", line 4, in inner UnboundLocalError: local variable 'x' referenced before assignment >>>
為了解決這個問題,我們可以加上 nonlocal 關鍵字,告訴 inner 函數,這不是一個本地變量:
>>> 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 >>>
有沒有發現,x 的值竟然被保存了下來,每次調用一下,就增加了 1,這就是閉包的妙處。
用閉包來替換遞歸
利用上述閉包會保留調用結果的特性,我們可以用這個來替換遞歸,比如利用閉包計算斐波那契數列:
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(): ... 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 >>>
而使用遞歸方法計算斐波那契數列的方法如下所示:
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) 就可以計算出結果:
In [4]: fib_closure(20) Out[4]: 6765 In [5]: fib_recursion(20) Out[5]: 6765 In [6]:
現在使用 IPython 來測試下這兩者的性能:
In [6]: %time fib_closure(20) CPU times: user 10 µs, sys: 1e+03 ns, total: 11 µs Wall time: 14.1 µs Out[6]: 6765 In [7]: %time fib_recursion(20) CPU times: user 2.76 ms, sys: 15 µs, total: 2.78 ms Wall time: 2.8 ms Out[7]: 6765
可以看出兩差相差近 1000 倍,這還只是計算到第 20 個數的情況下,如果計算到 100,那使用遞歸會計算很久甚至無法計算出來。
閉包的其他用處
Python 的閉包不僅僅用于替換遞歸,還有很多場景可以使用閉包。比如學生成績的分類函數:
學生成績數據:
students = { 'Alice': 98, 'Bob': 67, 'Chris': 85, 'David': 75, 'Ella': 54, 'Fiona': 35, 'Grace': 69 }
現在需要根據學生成績進行分類,通常情況下我們會寫多個函數來進行分類,而分類的標準又會經常變化,這時候閉包就很方便了:
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)
如果分類標準變化,直接個性函數的參數即可,主要代碼邏輯不變,如果想查找成績分類為 A 的學生,只需要調用 grade_A(students) 即可:
In [13]: grade_A(students) Out[13]: {'Alice': 98, 'Chris': 85}
閉包使用上述分類函數很容易修改且更加易讀。
“如何使用閉包方法”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注創新互聯網站,小編將為大家輸出更多高質量的實用文章!