1. 程式人生 > >Python-裝飾器以及對帶有引數的裝飾器的理解

Python-裝飾器以及對帶有引數的裝飾器的理解

請編寫一個decorator,能在函式呼叫的前後打印出’begin call’和’end call’的日誌。
再思考一下能否寫出一個@log的decorator,使它既支援:

@log
def f():
    pass

又支援:

@log('execute')
def f():
    pass

下面是我的作業

def fonca(text):
    if callable(text):#有問題的部分,見下文.
        def foncb(*a):
            print 'start'
            returnVal=text(*a)
            print
'end' return returnVal else: def foncb(fonc): def foncc(*a2,**b2): print '%s'%text print 'start' returnVal=fonc(*a2,**b2) print 'end' return returnVal return foncc return
foncb @fonca def fonc(): print 'fonc\'s running' # @fonca('hello') # def fonc(): # print 'fonc\'s running' print fonc()

在上面註釋的部分,我遇到了問題,我曾經是這麼寫的:

if callable(text):
        def foncb(text):
            def foncc(*a):
                print 'start'
                returnVal=text(*a)
                print
'end' return returnVal return foncb

會報錯:

print fonc()
TypeError: foncb() takes exactly 1 argument (0 given)

關於這個問題我研究了好久,雖然不確定自己想的對不對,如果有大神看到請不吝賜教.
最開始我想,就算使用三層巢狀的裝飾器是不是也可以處理兩層巢狀裝飾器的問題(原諒我的描述不清),只要我也把fonc()一層一層傳進去就好了,然是事情並不是這樣的.
錯誤三層巢狀程式碼執行起來是這樣的:
這裡寫圖片描述
正確三層巢狀程式碼執行起來是這樣的:
這裡寫圖片描述
我的理解是這樣的,下面的話都是我的猜測:
Python就像是一個工廠,只要他發現自己已經拿到了最終的原料,也就是這裡的fonc(),就會開始生產.
所以對於錯誤的程式碼,就是在第二層巢狀裡就拿到了fonc(),立刻執行生產,所以報錯.
對於正確的程式碼,在第二層巢狀裡拿到的還是foncb(fonc)還要拆開包裹才能拿到fonc()所以Python不急於生產,繼續執行.

如理解有誤還請大神指教(〃 ̄︶ ̄)人( ̄︶ ̄〃)