導航:首頁 > 編程語言 > python回調裝飾

python回調裝飾

發布時間:2022-09-18 14:47:22

① 什麼是python裝飾器


所謂裝飾器就是把函數包裝一下,為函數添加一些附加功能,裝飾器就是一個函數,參數為被包裝的函數,返回包裝後的函數:你可以試下:

defd(fp):
def_d(*arg,**karg):
print"dosthbeforefp.."
r=fp(*arg,**karg)
print"dosthafterfp.."
returnr
return_d
@d
deff():
print"callf"
#上面使用@d來表示裝飾器和下面是一個意思
#f=d(f)
f()#調用f



② python回調函數的使用方法

python回調函數的使用方法
在計算機程序設計中,回調函數,或簡稱回調(Callback),是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計允許了底層代碼調用在高層定義的子程序
有兩種類型的回調函數:

那麼,在python中如何實現回調函數呢,看代碼:
代碼如下:

def my_callback(input):
print "function my_callback was called with %s input" % (input,)

def caller(input, func):
func(input)

for i in range(5):
caller(i, my_callback)

③ 如何理解Python裝飾器

理解Python中的裝飾器
@makebold
@makeitalic
def say():
return "Hello"

列印出如下的輸出:
<b><i>Hello<i></b>

你會怎麼做?最後給出的答案是:

def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped

def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped

@makebold
@makeitalic
def hello():
return "hello world"

print hello() ## 返回 <b><i>hello world</i></b>

現在我們來看看如何從一些最基礎的方式來理解Python的裝飾器。英文討論參考Here。
裝飾器是一個很著名的設計模式,經常被用於有切面需求的場景,較為經典的有插入日誌、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
1.1. 需求是怎麼來的?
裝飾器的定義很是抽象,我們來看一個小例子。

def foo():
print 'in foo()'
foo()

這是一個很無聊的函數沒錯。但是突然有一個更無聊的人,我們稱呼他為B君,說我想看看執行這個函數用了多長時間,好吧,那麼我們可以這樣做:

import time
def foo():
start = time.clock()
print 'in foo()'
end = time.clock()
print 'used:', end - start

foo()

很好,功能看起來無懈可擊。可是蛋疼的B君此刻突然不想看這個函數了,他對另一個叫foo2的函數產生了更濃厚的興趣。
怎麼辦呢?如果把以上新增加的代碼復制到foo2里,這就犯了大忌了~復制什麼的難道不是最討厭了么!而且,如果B君繼續看了其他的函數呢?
1.2. 以不變應萬變,是變也
還記得嗎,函數在Python中是一等公民,那麼我們可以考慮重新定義一個函數timeit,將foo的引用傳遞給他,然後在timeit中調用foo並進行計時,這樣,我們就達到了不改動foo定義的目的,而且,不論B君看了多少個函數,我們都不用去修改函數定義了!

import time

def foo():
print 'in foo()'

def timeit(func):
start = time.clock()
func()
end =time.clock()
print 'used:', end - start

timeit(foo)

看起來邏輯上並沒有問題,一切都很美好並且運作正常!……等等,我們似乎修改了調用部分的代碼。原本我們是這樣調用的:foo(),修改以後變成了:timeit(foo)。這樣的話,如果foo在N處都被調用了,你就不得不去修改這N處的代碼。或者更極端的,考慮其中某處調用的代碼無法修改這個情況,比如:這個函數是你交給別人使用的。
1.3. 最大限度地少改動!
既然如此,我們就來想想辦法不修改調用的代碼;如果不修改調用代碼,也就意味著調用foo()需要產生調用timeit(foo)的效果。我們可以想到將timeit賦值給foo,但是timeit似乎帶有一個參數……想辦法把參數統一吧!如果timeit(foo)不是直接產生調用效果,而是返回一個與foo參數列表一致的函數的話……就很好辦了,將timeit(foo)的返回值賦值給foo,然後,調用foo()的代碼完全不用修改!

#-*- coding: UTF-8 -*-
import time

def foo():
print 'in foo()'

# 定義一個計時器,傳入一個,並返回另一個附加了計時功能的方法
def timeit(func):

# 定義一個內嵌的包裝函數,給傳入的函數加上計時功能的包裝
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'used:', end - start

# 將包裝後的函數返回
return wrapper

foo = timeit(foo)
foo()

這樣,一個簡易的計時器就做好了!我們只需要在定義foo以後調用foo之前,加上foo = timeit(foo),就可以達到計時的目的,這也就是裝飾器的概念,看起來像是foo被timeit裝飾了。在在這個例子中,函數進入和退出時需要計時,這被稱為一個橫切面(Aspect),這種編程方式被稱為面向切面的編程(Aspect-Oriented Programming)。與傳統編程習慣的從上往下執行方式相比較而言,像是在函數執行的流程中橫向地插入了一段邏輯。在特定的業務領域里,能減少大量重復代碼。面向切面編程還有相當多的術語,這里就不多做介紹,感興趣的話可以去找找相關的資料。
這個例子僅用於演示,並沒有考慮foo帶有參數和有返回值的情況,完善它的重任就交給你了 :)
上面這段代碼看起來似乎已經不能再精簡了,Python於是提供了一個語法糖來降低字元輸入量。

import time

def timeit(func):
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'used:', end - start
return wrapper

@timeit
def foo():
print 'in foo()'

foo()

重點關注第11行的@timeit,在定義上加上這一行與另外寫foo = timeit(foo)完全等價,千萬不要以為@有另外的魔力。除了字元輸入少了一些,還有一個額外的好處:這樣看上去更有裝飾器的感覺。
-------------------
要理解python的裝飾器,我們首先必須明白在Python中函數也是被視為對象。這一點很重要。先看一個例子:

def shout(word="yes") :
return word.capitalize()+" !"

print shout()
# 輸出 : 'Yes !'

# 作為一個對象,你可以把函數賦給任何其他對象變數

scream = shout

# 注意我們沒有使用圓括弧,因為我們不是在調用函數
# 我們把函數shout賦給scream,也就是說你可以通過scream調用shout

print scream()
# 輸出 : 'Yes !'

# 還有,你可以刪除舊的名字shout,但是你仍然可以通過scream來訪問該函數

del shout
try :
print shout()
except NameError, e :
print e
#輸出 : "name 'shout' is not defined"

print scream()
# 輸出 : 'Yes !'

我們暫且把這個話題放旁邊,我們先看看python另外一個很有意思的屬性:可以在函數中定義函數:

def talk() :

# 你可以在talk中定義另外一個函數
def whisper(word="yes") :
return word.lower()+"...";

# ... 並且立馬使用它

print whisper()

# 你每次調用'talk',定義在talk裡面的whisper同樣也會被調用
talk()
# 輸出 :
# yes...

# 但是"whisper" 不會單獨存在:

try :
print whisper()
except NameError, e :
print e
#輸出 : "name 'whisper' is not defined"*

函數引用
從以上兩個例子我們可以得出,函數既然作為一個對象,因此:
1. 其可以被賦給其他變數
2. 其可以被定義在另外一個函數內
這也就是說,函數可以返回一個函數,看下面的例子:

def getTalk(type="shout") :

# 我們定義另外一個函數
def shout(word="yes") :
return word.capitalize()+" !"

def whisper(word="yes") :
return word.lower()+"...";

# 然後我們返回其中一個
if type == "shout" :
# 我們沒有使用(),因為我們不是在調用該函數
# 我們是在返回該函數
return shout
else :
return whisper

# 然後怎麼使用呢 ?

# 把該函數賦予某個變數
talk = getTalk()

# 這里你可以看到talk其實是一個函數對象:
print talk
#輸出 : <function shout at 0xb7ea817c>

# 該對象由函數返回的其中一個對象:
print talk()

# 或者你可以直接如下調用 :
print getTalk("whisper")()
#輸出 : yes...

還有,既然可以返回一個函數,我們可以把它作為參數傳遞給函數:

def doSomethingBefore(func) :
print "I do something before then I call the function you gave me"
print func()

doSomethingBefore(scream)
#輸出 :
#I do something before then I call the function you gave me
#Yes !

這里你已經足夠能理解裝飾器了,其他它可被視為封裝器。也就是說,它能夠讓你在裝飾前後執行代碼而無須改變函數本身內容。
手工裝飾
那麼如何進行手動裝飾呢?

# 裝飾器是一個函數,而其參數為另外一個函數
def my_shiny_new_decorator(a_function_to_decorate) :

# 在內部定義了另外一個函數:一個封裝器。
# 這個函數將原始函數進行封裝,所以你可以在它之前或者之後執行一些代碼
def the_wrapper_around_the_original_function() :

# 放一些你希望在真正函數執行前的一些代碼
print "Before the function runs"

# 執行原始函數
a_function_to_decorate()

# 放一些你希望在原始函數執行後的一些代碼
print "After the function runs"

#在此刻,"a_function_to_decrorate"還沒有被執行,我們返回了創建的封裝函數
#封裝器包含了函數以及其前後執行的代碼,其已經准備完畢
return the_wrapper_around_the_original_function

# 現在想像下,你創建了一個你永遠也不遠再次接觸的函數
def a_stand_alone_function() :
print "I am a stand alone function, don't you dare modify me"

a_stand_alone_function()
#輸出: I am a stand alone function, don't you dare modify me

# 好了,你可以封裝它實現行為的擴展。可以簡單的把它丟給裝飾器
# 裝飾器將動態地把它和你要的代碼封裝起來,並且返回一個新的可用的函數。
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#輸出 :
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

現在你也許要求當每次調用a_stand_alone_function時,實際調用卻是a_stand_alone_function_decorated。實現也很簡單,可以用my_shiny_new_decorator來給a_stand_alone_function重新賦值。

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#輸出 :
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

# And guess what, that's EXACTLY what decorators do !

裝飾器揭秘
前面的例子,我們可以使用裝飾器的語法:

@my_shiny_new_decorator
def another_stand_alone_function() :
print "Leave me alone"

another_stand_alone_function()
#輸出 :
#Before the function runs
#Leave me alone
#After the function runs

當然你也可以累積裝飾:

def bread(func) :
def wrapper() :
print "</''''''\>"
func()
print "<\______/>"
return wrapper

def ingredients(func) :
def wrapper() :
print "#tomatoes#"
func()
print "~salad~"
return wrapper

def sandwich(food="--ham--") :
print food

sandwich()
#輸出 : --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#outputs :
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

使用python裝飾器語法:

@bread
@ingredients
def sandwich(food="--ham--") :
print food

sandwich()
#輸出 :
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>

④ 如何在Python使用裝飾器來注冊回調函數

之前一直知道裝飾器可以增強一個已經存在的方法,Python也提供了annotation的方法,很好用. 但是再看flask login的擴展包的時候. 發現裝飾器還可以實現回調函數的注冊功能.
flask login就是通過下面的裝飾器,來注冊回調函數,當沒有sessionID時,通過裝飾器指定的函數來讀取用戶到session中.
@login_manager.user_loader
下面寫了一個簡單的測試例子來演示這個功能.
import time
import functools
class Test():
#/**feature將調用callback(), 但是在Test中並沒有真正的定義callback**/
def feature(self):
self.callback()
def decorate(self, func):
self.callback=func
return func
test = Test()
#/**將foo注冊為回調函數*//
@test.decorate
def foo():
print 'in foo()'
#/**調用feature將觸發回調函數**/
test.feature()

⑤ python裝飾器的作用和功能

裝飾器本質上是一個Python函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數對象。它經常用於有切面需求的場景,比如:插入日誌、性能測試、事務處理、緩存、許可權校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能

⑥ python 裝飾器部分 裝飾器返回值與函數返回值 混亂了

@deco
def my():
# your code list

python 會解釋成:my = deco(my)
所以你實際上外面調用 my()函數時,調用的是deco 裡面的wrapfunc(),返回值就是
wrapfunc()的返回值,即"return times"。
一個函數要返回兩個值是不現實的,你的需求可能是同時保存函數值和調用花費的時間
(或者簡單的列印出來而已?看你的需求了),略該如下(引入全局變數保存……):

funcall_cost = 0
def deco(func):
def wrapfunc(*args, **kwrags):
global funcall_cost
now = time()
result = func(*args, **kwargs)
funcall_cost = time() - now
return result
return wrapfunc

⑦ 如何理解Python裝飾器

簡單來講,可以不嚴謹地把Python的裝飾器看做一個包裝函數的函數。
比如,有一個函數:
def func():
print 'func() run.'

if '__main__' == __name__:
func()

運行後將輸出:
func() run.

現在需要在函數運行前後列印一條日誌, 但是又不希望或者沒有許可權修改函數內部的結構, 就可以用到裝飾器(decorator):
def log(function):
def wrapper(*args, **kwargs):
print 'before function [%s()] run.' % function.__name__
rst = function(*args, **kwargs)
print 'after function [%s()] run.' % function.__name__
return rst
return wrapper

@log
def func():
print 'func() run.'

if '__main__' == __name__:
func()

對於原來的函數"func()"並沒有做修改,而是給其使用了裝飾器log,運行後的輸出為:
before function [func()] run.
func() run.
after function [func()] run.

把"@log"放到func()函數定義的地方,相當於執行了如下語句:
func = log(func)

因為log()返回了一個函數, 所以原本的func指向了log()返回的函數wrapper。wrapper的參數列表為(*args, **kwargs), 所以其可以接受所有的參數調用, 在wrapper中,先列印了一行
'before function [%s()] run.' % function.__name__
(在Python中函數也是對象,函數的__name__是它的名字),然後執行了原來的函數並記錄了返回值,在輸出
'after function [%s()] run.' % function.__name__
後返回了函數的執行結果。
如果decorator本身需要傳入參數,那就需要編寫一個返回decorator的decorator。比如在Flask中:
@app.route('/')
def index():
return 'hello, world!'

實現如下:
import functools

def log(text=''):
def decorator(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
print 'before function [%s()] run, text: [%s].' % (function.__name__, text)
rst = function(*args, **kwargs)
print 'after function [%s()] run, text: [%s].' % (function.__name__, text)
return rst
return wrapper
return decorator

@log('log text')
def func():
print 'func() run.'

if '__main__' == __name__:
func()

輸出如下:
before function [func()] run, text: [log text].
func() run.
after function [func()] run, text: [log text].

最後腦洞小開一下, 有沒有辦法實現既支持不帶參數(如log), 又支持帶參數(如log('text'))的decorator嗎?
import functools

def log(argument):
if not callable(argument):
def decorator(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
print 'before function [%s()] run, text: [%s].' % (function.__name__, text)
rst = function(*args, **kwargs)
print 'after function [%s()] run, text: [%s].' % (function.__name__, text)
return rst
return wrapper
return decorator
def wrapper(*args, **kwargs):
print 'before function [%s()] run.' % function.__name__
rst = argument(*args, **kwargs)
print 'after function [%s()] run.' % function.__name__
return rst
return wrapper

⑧ python中的urlretrieve回調函數怎麼用

回調函數,顧名思義,也就是等該函數執行完了,會回去調用我們傳進去的函數。用到回調函數的地方有不少,像我見過的:SQLite中的一個函數,sqlite_exec函數名有沒有記錯我沒什麼印象了。待這個函數執行完畢後,會去調用我傳進去的一個函數,一般回調函數都是有自己的參數列表格式的,再利用這個格式從回調函數中獲取到我們需要的一些值。

⑨ 剛學一個星期的小白求教關於python裝飾器

fromfunctoolsimportwraps


deflog(func):
@wraps(func)
defwrapper(*args,**kw):
print('begincall:%s()'%func.__name__)
#這里返回的是被裝飾的函數的返回值,如果注釋了,參見add_3
#returnfunc(*args,**kw)
returnwrapper


@log
defnow():
print('2015-3-25')


@log
defadd_3(int_val):
return3+int_val

now()
print(add_3(4))#這就沒有輸出了,應該可以解釋了

⑩ python裝飾器使用

裝飾器是從英文decorator翻譯過來的,從字面上來看就是對某個東西進行修飾,增強被修飾物的功能,下面我們對裝飾器做下簡單介紹。

一、怎麼編寫裝飾器

裝飾器的實現很簡單,本質是一個可調用對象,可以是函數、方法、對象等,它既可以裝飾函數也可以裝飾類和方法,為了簡單說明問題,我們實現一個函數裝飾器,如下代碼:

有了這個裝飾器,我們就可以列印出什麼時候開始和結束調用函數,對於排查函數的調用鏈非常方便。

二、帶參數的裝飾器

上面的例子無論什麼時候調用sum都會輸出信息,如果我們需要按需輸出信息怎麼實現呢,這時就要用到帶參數的裝飾器了,如下代碼:

對sum使用裝飾器時沒有參數,這時debug為0,所以調用sum時不會輸出函數調用相關信息。

對multi使用裝飾器時有參數,這時debug為1,所以調用multi時會輸出函數調用相關信息。

三、函數名字問題

當我們列印被裝飾後的函數名字時,不知道大家有沒發現輸出的不是函數本身的名字,如下代碼會輸出『wrap』而不是『sum』:

有時這種表現並不是我們想要的,我們希望被裝飾後的函數名字還是函數本身,那要怎麼實現呢?很簡單,只需要引入functools.wraps即可,如下代碼就會輸出『sum』了:

看完後是不是覺得python裝飾器很簡單,只要了解它的本質,怎麼寫都行,有好多種玩法呢。

閱讀全文

與python回調裝飾相關的資料

熱點內容
apachephpjava 瀏覽:274
伺服器旁為什麼要有電腦 瀏覽:522
什麼樣的app上買機票最便宜 瀏覽:987
安卓如何查看異常重啟 瀏覽:717
解壓音樂排名 瀏覽:386
安卓手機瀏覽器怎麼掃二維碼 瀏覽:721
通達信成本均線源碼 瀏覽:619
可以下載的解壓音頻 瀏覽:568
海賊王怎麼換伺服器 瀏覽:321
計算機上的共享文件夾映射 瀏覽:944
榮耀安裝包在文件夾哪裡 瀏覽:198
機票php源碼 瀏覽:235
linux共享mac 瀏覽:926
中國沒有國外的伺服器地址 瀏覽:761
為什麼退款伺服器連接錯誤 瀏覽:559
android簡訊存儲位置 瀏覽:977
unix網路編程卷4 瀏覽:808
找靚機app下單什麼時候發貨 瀏覽:413
android一個應用兩個進程 瀏覽:804
linux硬碟復制 瀏覽:808