對於Python中回撥函式的理解

王明輝發表於2017-12-30

  關於回撥函式,網上有很多說明和各種解釋,多數在嘗試用語言描述。我認為,如果對各個角色之間的關係不清楚,如果沒有相關的程式設計需求,那麼語言便非常無力,很難理解。

這是360百科的解釋:

  在計算機程式設計中,回撥函式,或簡稱回撥,是指通過函式引數傳遞到其它程式碼的,某一塊可執行程式碼的引用。這一設計允許了底層程式碼呼叫在高層定義的子程式
  【什麼是其它程式碼?什麼是某一塊?什麼是可執行?什麼是引用?什麼是允許?什麼是底層程式碼?什麼是高層定義?什麼是子程式?這些詞,每一個詞都有很多含義,如果你理解回撥,那麼這個定義描述得非常準確,如果你不理解回撥,那麼等於沒說,文字都認識,連起來不知道啥意思。】

這是知乎的一個解釋:

  https://www.zhihu.com/question/19801131

還有些用指標來進行說明

   如果一個人不知道回撥,他很可能也不瞭解指標這個C語言中的核心。

 

一圖解千言,一例解千言,下面是一個python中的回撥函式例子,可能可以有效地說明什麼是回撥函式。這個栗子用於下載時展現下載進度。

urlretrieve(url, filename=None, reporthook=None, data=None)

這是urllib.request中的一個函式,用於直接將遠端資料下載到本地。

  • url是你要下載的連結
  • 引數 finename 指定了儲存本地路徑(如果引數未指定,urllib會生成一個臨時檔案儲存資料。)
  • 引數 reporthook 是一個回撥函式,當連線上伺服器、以及相應的資料塊傳輸完畢時會觸發該回撥,我們可以利用這個回撥函式來顯示當前的下載進度
  • 引數 data 指 post 到伺服器的資料,該方法返回一個包含兩個元素的(filename, headers)元組,filename 表示儲存到本地的路徑,header 表示伺服器的響應頭。

  注意看reporthook,現假設你作為一名使用Python做開發的程式設計師,你不是在為Python開發外掛,而是在用現成的外掛去實現你的功能,那麼,Python語言和它的外掛,整體上是封閉的,假設你看不到Python的原始碼。

  此時,你要使用urlretrieve這個函式,分以下幾種情況:

  1.你可以只用一個引數的,即urlretrieve(url),那麼你只能把遠端的連結所開啟的頁面存到本地這個單純的動作,沒有其它功能和反饋。

  2.除了檢視那個實際下載的檔案是否完成和在控制檯中檢視程式的執行結束以外,實際上你無法知道1的進度,也無法知道是否下載成功。那麼,此時reporthook就有作用了,你需要給urlretrieve傳一個你本地函式的名字,帶著3個引數(假設這個函式是func(a,b,c),函式名是func),在你無法看到的urlretrieve內部,必要的時候,它會呼叫你傳給它的這個函式(func),把合適的資料賦給這個func的3個引數,然後,你就可以在你本地處理這3個引數,比如,顯示出來。

  這三個引數,按順序分別表示:已經下載的資料塊、資料塊的大小、遠端檔案的大小,得到這幾個資料,我們就可以得到下載的進度。

  以下是官方文件中的說明:

   If reporthook is given, it must be a function accepting three numeric parameters: A chunk number, the maximum size chunks are read in and the total size of the download (-1 if unknown). It will be called once at the start and after each chunk of data is read from the network. reporthook is ignored for local URLs.

來源:https://docs.python.org/3.6/library/urllib.request.html#module-urllib.request

以下是程式碼:

import urllib

def cbk(a, b, c): 

    '''回撥函式
    @a: 已經下載的資料塊
    @b: 資料塊的大小
    @c: 遠端檔案的大小
    ''' 
    per = 100.0 * a * b / c 

    if per > 100: 
        per = 100 
    print('%.2f%%' % per)
   
url = 'http://www.bing.com'
local = 'd://bing.html'
urllib.urlretrieve(url, local, cbk)

(以上程式碼來自http://www.nowamagic.net/academy/detail/1302861

這是你作為一個使用者,使用別人設計好的函式時的情況。

 

 

 

相關文章