---
# System prepended metadata

title: Python - Decorator
tags: [Python]

---

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