# Python - Decorator ###### tags: `Python` 查看: https://docs.pythontab.com/interpy/decorators/deco_class/ https://foofish.net/magic-method.html ```python= def a_new_decorator(a_func): def wrap_the_func(): print("do something before the func!") a_func() print("do something after the func!") return wrap_the_func def a_func_requiring_decorator(): print("I am the function being decoratored.") a_func_requiring_decorator() a_func_requiring_decorator = a_new_decorator(a_func_requiring_decorator) # decorator的功能即是包裝每一個func,讓你可以統一在這些func前後重複作一些事,減少重複的code a_func_requiring_decorator() # 以下是簡化版本 def a_new_decorator(a_func): def wrap_the_func(): print("do something before the func!") a_func() print("do something after the func!") return wrap_the_func @a_new_decorator def a_func_requiring_decorator(): print("I am the function being decoratored.") a_func_requiring_decorator() # 以上作法會出現一個問題,a_func_requiring_decorator在被裝飾器裝飾過,他的func name會被覆寫成wrap_the_func,導致print(a_function_requiring_decoration.__name__) => Output: wrapTheFunction # 解法 # @wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。 from functools import wraps def a_new_decorator(a_func): @wraps(a_func) def wrap_the_func(): print("do something before the func!") a_func() print("do something after the func!") return wrap_the_func @a_new_decorator def a_func_requiring_decorator(): print("I am the function being decoratored.") a_func_requiring_decorator() print(a_func_requiring_decorator.__name__) # decorator example - Logging # print the log in the begining of every func from functools import wraps def logit(func): @wraps(func) def wrap_the_func(*args, **kargs): print(func.__name__ + "was called.") return func(*args, **kargs) return wrap_the_func @logit def add_func(x): return x+x @logit def del_func(x): return x-x add_res = add_func(4) del_res = del_func(4) print(add_res) print(del_res) # 讓裝飾器接受參數,外面在包一層接參數,裡面return的才是decorator from functools import wraps def logit(log_file = "out.log"): def logging_decorator(func): @wraps(func) def wrap_the_func(*args, **kargs): log_string = func.__name__ + " was called." print(log_string) with open(log_file, 'a') as open_filed: open_filed.write(log_string + '\n') return func(*args, **kargs) return wrap_the_func return logging_decorator def myfunc1(): pass myfunc1 = logit(log_file = "out1.log")(myfunc1) myfunc1() @logit(log_file = "out2.log") def myfunc2(): pass myfunc2() # 上述的函式裝飾器只能是用一種情境,如果針對不同的情境你想要有不同的處理,更好的是用Class搭配繼承 # 寫一個decorator class from functools import wraps class logit: """docstring for logit""" def __init__(self, logfile = "log.out"): self.logfile = logfile def __call__(self, func): @wraps(func) def wrap_the_func(): log_string = func.__name__ + "was called." print(log_string) with open(self.logfile, 'a') as open_filed: open_filed.write(log_string + '\n') self.notify() return func return wrap_the_func def notify(self): pass @logit("test") def myfunc1(): pass myfunc1() # https://stackoverflow.com/questions/11179008/python-inheritance-typeerror-object-init-takes-no-parameters class email_logit(logit): def __init__(self, email='admin@myproject.com', logfile='log.out'): self.email = email # super(email_logit, self).__init__(logfile) super().__init__(logfile) def notify(self): print("in email ", self.email) pass @email_logit(email="jack", logfile="test2") def myfunc2(): pass myfunc2() ```