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

2014年7月23日 星期三

Python - 抽象類別

Python的library中,有東西能協助建立抽象類別與抽象方法。
from abc import ABCMeta, abstractmethod  # abstract class

class base(metaclass = ABCMeta):
   
    @abstractmethod
    def foo(self):
        pass
如此一來,繼承base類別就一定要覆寫foo方法。

Python - decorator運用(2)

在撰寫函式時,因為python的特性,不會去檢查回傳值的資料型態是否正確,也不會去檢查是否遺漏回傳值,這對於撰寫複雜一點的函式容易有疏忽的地方,這時候就能靠decorator做一些協助,例如遺漏回傳值時補上預設回傳值,或者回傳值型態錯誤時丟出例外錯誤。
import functools

## Check return type and value.
#  @details The return value could be one following situation:
#            1. value type is specified in the \a cls;
#            2. None;
#            3. value type is not specified and not None.
#   
#            In the 1st situation, return original value.
#            In the 2nd situation, if allow_none is true, return None; otherwise, return \a default.
#            In the 3rd situation, raise SyntaxError.
#  @param   default is the default return value.
#  @param   cls is the specified return value type.
#  @param   allow_none - if true, the return value could be None; otherwise, the return value must be assigned.
#  @exception   SyntaxError

def checkReturn(default, allow_type = None, allow_none = False):
   
    def check_decorator(function):
       
        def decorator_wrapper(*args, **kwargs):
            result = function(*args, **kwargs)
           
            cls = allow_type
            try:
                if allow_type is None:
                    cls = (type(default),)
                elif not issubclass(allow_type, tuple):
                    cls = (allow_type,)
            except Exception as e:
                raise
           
            if type(result) in cls:
                pass
            elif result is None:
                if allow_none:
                    pass
                else:
                    result = default
            else:
                raise SyntaxError("The type of return value {0} is not in {1}.".format(result, cls))
            return result
       
        return decorator_wrapper
   
    return check_decorator

Python - decorator運用(1)

在trace程式碼的時候,尤其是多執行緒的程式碼,想知道函式的呼叫情況,此時會記錄函式的進出資訊。在python,可以使用decorator幫助記錄。
import functools
import time

def logFunc(logger = None):
   
    def log_decorator(function):
       
        @functools.wraps(function)
        def decorator_wrapper(*args, **kwargs):
            if logger is None:
                print("{2} [Debug] Enter {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
                result = function(*args, **kwargs)
                print("{2} [Debug] Exit {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
            else:
                logger.debug("Enter {0}.{1}".format(function.__module__, function.__name__))
                result = function(*args, **kwargs)
                logger.debug("Exit {0}.{1}".format(function.__module__, function.__name__))
            return result
       
        return decorator_wrapper
   
    return log_decorator

另外,有時需要記錄函式的執行時間,一樣可以使用decorator幫助記錄。
import functools
import time

def logTime(logger = None):
   
    def time_decorator(function):
       
        def decorator_wrapper(*args, **kwargs):
            start = time.time()
            result = function(*args, **kwargs)
            end = time.time()
            if logger is None:
                print("{3} [Debug] {0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start, time.asctime()))
            else:
                logger.debug("{0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start))
            return result
       
        return decorator_wrapper
   
    return time_decorator

在這裡的logger是指logging.logger。

decorator的使用方式為:
@logFunc(logger)
def foo1():
  # expressions

@logTime(logger)
def foo2():
  # expressions