2016-09-21 63 views
0

最近我在學Python裝飾器和使用functools.wrapspython裝飾器如何更改__name__

def a(): 
    def b(): 
     def c(): 
      print('hello') 
     return c 
    return b 


print a.__name__ 
#output:a 

我明白爲什麼輸出a.But我不知道如何在下面的代碼__name__變化。

def log(text): 
    def decorator(func): 
     def wrapper(*args, **kw): 
      print('%s %s():' % (text, func.__name__)) 
      return func(*args, **kw) 
     return wrapper 
    return decorator 

@log('...') 
def simple(): 
    print('*' * 20) 

print simple.__name__ 
#output:wrapper 

爲什麼輸出是'包裝'而不是'裝飾者'或'日誌'?

+0

也許不那麼相關的功能,但你應該看看[什麼'functools.wraps'做?](http://stackoverflow.com/questions/308999/what-does-functools-wraps-do) –

+1

你知道裝飾者如何在內部工作嗎?重寫它沒有語法糖有助於理解這裏發生的事情。 –

回答

2

一些基本知識:

@decorator 
def f(): 
    pass 

等同於:

def f(): 
    pass 
f = decorator(f) 

裝飾與ARGS:

@decorator(*args, **kwargs) 
def f(): 
    pass 

等同於:

def f(): 
    pass 
decorator_instance = decorator(*args, **kwargs) 
f = decorator_instance(f) 

隨着瞭解的話,我們可能會重寫你的例子:

def simple(): 
    print('*' * 20) 

log_instance = log('...') 
simple = log_instance(simple) 

我們來分析一下在最後兩行會發生什麼:

  • log_instancedecorator功能和文本變量中它等於' ...「
  • 由於decorator(無論text值)返回名爲包裝函數,simple替換名爲wrapper
0

修飾者的要點是替換函數或類與裝飾器返回的內容,當用該函數/類作爲參數調用時。具有參數的裝飾器更復雜一些,因爲首先調用外部方法(log)以獲取「參數化」裝飾器(decorator),然後調用該裝飾器並獲得最終函數(wrapper),該函數將替換裝飾後的函數(simple)。

因此,與simple給它一些結構,

  1. 呼叫log'...'作爲參數,獲得decorator
  2. 呼叫decorator作爲參數,獲得wrapper
  3. wrapper
更換 simple
0
@log('...') 
def simple(... 

相當於

def simple(... 
simple = log('...')(simple) 

所以log實際上是所謂的,返回decorator,這被稱爲與simple作爲參數,然後通過decorator的返回值,這是功能wrapper,因而其__name__是取代wrapper