# 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()
```