網頁

顯示具有 decorator 標籤的文章。 顯示所有文章
顯示具有 decorator 標籤的文章。 顯示所有文章

2015年7月4日 星期六

[Python] decorator的等價寫法

主題: decorator的等價寫法


class A(object):
    @property
    def func(self):
       ...



class A(object):
    def func(self):
       ...
    func = property(func)

換句話說這時候 func經過property之後
1. 從單純的func變成為property
2. func則變為 class variable (不是intance variable)


2015年6月25日 星期四

[Python][Metaprogramming] 9.1 decorator

介紹@wraps decorator


沒加@wraps

<pre class='codeblock'>#!/usr/bin/python

import time
from functools import wraps

def timethis(func):
 '''
 Decorator that reports the excution time
 '''
 #@wraps(func)
 def wrapper(*args, **kwargs):
  start = time.time()
  result = func(*args, **kwargs)
  end = time.time()
  print(func.__name__, end-start)
  return result
 return wrapper

@timethis
def countdown(n):
 '''
 Counts down
 '''
 while n > 0:
  n -= 1


countdown(10000)
print countdown.__name__
print countdown.__doc__

<\pre>

結果:

'countdown', 0.00028896331787109375) 
wrapper
None

有加@wraps

結果:

('countdown', 0.00029587745666503906) 
countdown 
Counts down

結論:

寫decorator若想保留原來的funcion __name__, __doc__那就要加 @wraps
否則就會被替換成 wrapper, None

2015年5月6日 星期三

python decorator

只是筆記一下

目的:
假設我們想要對某些function的回傳值做一個簡單的處理:
如果回傳值昰list且指有一個元素就直接取出(不放在list裡面)

def unpack_list_for_one_item(fn):                                                                            
    "unpack list for one item, if fn return ['5.1'] than return '5.1'"                                        
    def decorator(*args, **kwargs):                                                                          
        fnRet = fn(*args, **kwargs)                                                                          
        if not isinstance(fnRet, list):                                                                      
            raise TypeError("The decorator-unpack_list_for_one_item input fn{0}'s result shall be list type".format(fn))                                                                                                      
                                                                                                             
        return fnRet[0] if 1==len(fnRet) else fnRet                                                          
    return decorator                                                                                          

用法:
    @unpack_list_for_one_item
    def major(self):      
       ....

    @unpack_list_for_one_item
    def minor(self):      
       ....

    @unpack_list_for_one_item
    def patPath(self):      
       ....

解說:
1. decorator如果沒有額外參數input和output都是function
2. decorator即使沒有被呼叫也會被run過(第一層),且在main之前就被run過,如下:
#!/usr/bin/python3

from functools import wraps, partial
import logging

def logged(func):
        print ("%r %s" % (locals(), "0"))
        def innerDecorate(*args, **kwargs):
                print ("%r %s" % (locals(), "1"))
                return func
        return innerDecorate

@logged
def add(x, y):
        return x + y


注意, add並沒有被呼叫, 但結果如下:
{'func': <function add at 0x7f6798c77170>} 0

這表示 print ("%r %s" % (locals(), "0")) 有被執行
並且注意 print ("%r %s" % (locals(), "1")) 沒有被執行

但注意我們只是對func加上decorator

那如果是有參數的decorator會如何?
#!/usr/bin/python3



from functools import wraps, partial

import logging





def logged(level, name=None, message=None):

        print ("%r %s" % (locals(), "0"))

        def decorate(func):

                logname =  name if name else func.__module__

                log = logging.getLogger(logname)

                logmsg = message if message else func.__name__

                print ("%r %s" % (locals(), "1"))



                @wraps(func)

                def wrapper(*args, **kwargs):

                        print ("%r %s" % (locals(), "2"))

                        log.log(level, logmsg)

                        return func(*args, **kwargs)



                return wrapper

        return decorate



@logged(logging.DEBUG)

def add(x, y):

        return x + y


注意,一樣add並沒有被呼叫, 但結果如下:
{'message': None, 'level': 10, 'name': None} 0
{'message': None, 'logmsg': 'add', 'func': <function add at 0x7f8c9f649710>, 'logname': '__main__', 'name': None, 'log': <logging.Logger object at 0x7f8c9f66db10>, 'level': 10} 1

這表示 print ("%r %s" % (locals(), "0")) / print ("%r %s" % (locals(), "1"))  有被執行
並且注意 print ("%r %s" % (locals(), "2")) 沒有被執行