装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。 首先,让我们讨论下如何写你自己的装饰器。
这可能是最难掌握的概念之一。我们会每次只讨论一个步骤,这样你能完全理解它。
以上来自菜鸟教程
装饰器本身就是一个函数,它只不过是对另外一个函数进行了一次封装,它能够把那个函数的功能进行一个强化
#!/usr/bin/env python
def day1():
print("My function name is:", day1.__name__)
def main():
day1()
if __name__ == "__main__":
main()
>>> My function name is: day1
在以上代码块中定义了一个函数为:day1, 输出一句话为:My function name is: day1
,那么装饰器能够把原来的函数功能上进行一个强化的操作。 在以上函数中输出了一句话,若我们需要在输出一句话如:hello world
若没装饰器 如下:
#!/usr/bin/env python
def day1():
print("hello world")
print("My function name is:", day1.__name__)
def main():
day1()
if __name__ == "__main__":
main()
>>>
hello world
My function name is: day1
若有装饰器如下:
#!/usr/bin/env python
def day2(func):
print("hello world")
return func
@day2
def day1():
print("My function name is:", day1.__name__)
def main():
day1()
if __name__ == "__main__":
main()
>>>
hello world
My function name is: day1
在以上代码块中出现了@
符号,以及day2函数,现在不用管它是什么意思,以上代码已经实现了装饰器对原来的函数功能进行了一次强化,但是在第一个代码块中只需要加一句话就可以实现,但是在第二个代码中还需要在写一个函数,感觉会非常麻烦,但是如果被强化的函数有1万个,难道需要一行行去添加吗?,很显然是不可以的,所以接下来开始讲解装饰器。
加粗样式
在定义装饰器之前首先我们需要有一个函数,因为装饰器是对函数进行了一次封装同时对函数进行强化的作用。
def tony():
print("my function name is:", tony.__name__) # 每一个函数的名字都可以自带一个变量:__name__就是函数名它自己
def main():
tony()
if __name__ == "__main__":
main()
> my function name is: tony # 输出内容
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:", deco_iron.__name__)
return func
def tony():
print("my function name is:", tony.__name__)
def main():
tony()
if __name__ == "__main__":
main()
tony = deco_iron(tony)
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:", deco_iron.__name__)
return func
def tony():
print("my function name is:", tony.__name__)
name = deco_iron(tony)
def main():
name()
if __name__ == "__main__":
main()
开始运行: deco_iron
my function name is: tony
使用@符号如下:
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:", deco_iron.__name__)
return func
@deco_iron #---->tony = deco_iron(tony)
def tony():
print("my function name is:", tony.__name__)
def main():
tony()
if __name__ == "__main__":
main()
@deco_iron 就相当于 tony = deco_iron(tony)
如何嵌套两层函数
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:", deco_iron.__name__)
return func
def deco_iron2(func):
print("开始运行:", deco_iron2.__name__)
return func
@deco_iron2
@deco_iron #---->tony = deco_iron(tony)
def tony():
print("my function name is:", tony.__name__)
def main():
tony()
if __name__ == "__main__":
main()
>>>
开始运行: deco_iron
开始运行: deco_iron2
my function name is: tony
@deco_iron2 等于 tony = deco_iron2(deco_iton(tony))
在以上例子中,将tony
函数传入Deco_iron函数 只是输出了一段话就返回了tony 函数, 似乎并没有什么意义,接下来干点别的。
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:deco_iron......")
def wrapper():
print("开始运行wrapper..........")
func()
print("结束运行wrapper.............")
return wrapper
@deco_iron #---->tony = deco_iron(tony)
def tony():
print("my function name is:", tony.__name__)
def main():
tony()
if __name__ == "__main__":
main()
>>>
>开始运行:deco_iron......
开始运行wrapper..........
my function name is: wrapper
结束运行wrapper.............
可能以上代码在刚接触装饰器的时候会有点懵,不过没关系,我将会一一解读。
开始运行:deco_iron…
开始运行wrapper…
my function name is:wrapper
后续会解决此问题,请认真理解上图(关键!)
结束运行wrapper…
如何传入参数?
#!/usr/bin/env python
def deco_iron(func):
print("开始运行:deco_iron......")
def wrapper(*args, **kw):
print("开始运行:{}".format(func.__name__))
print(args, kw)
func(*args, **kw)
print("结束运行:{}".format(func.__name__))
return wrapper
@deco_iron #---->tony = deco_iron(tony)
def tony(name, age):
print("my function name is:", tony.__name__)
print(f"Your name is {name}, Your age is :{age}")
def main():
tony('yankerp', 13)
if __name__ == "__main__":
main()
开始运行:deco_iron......
开始运行:tony
('yankerp', 13) {}
my function name is: wrapper
Your name is yankerp, Your age is :13
结束运行:tony
给装饰器传参数
#!/usr/bin/env python
def deco_params(name):
def deco_iron(func):
print("开始运行:deco_iron......")
def wrapper(*args, **kw):
print("开始运行:{}".format(func.__name__))
print(args, kw)
func(*args, **kw)
print("结束运行:{}".format(func.__name__))
print(f"My name is :{name}".center(60, "-"))
return wrapper
return deco_iron
@deco_params("Yankerp")
def tony(*args, **kw):
print("my function name is:", tony.__name__)
def main():
tony('yankerp',80)
if __name__ == "__main__":
main()
开始运行:deco_iron......
开始运行:tony
('yankerp', 80) {}
my function name is: wrapper
结束运行:tony
--------------------My name is :Yankerp---------------------
解决原函数在装饰器后内存中改变的情况
#!/usr/bin/env python
from functools import wraps
def deco_params(name):
def deco_iron(func):
print("开始运行:deco_iron......")
@wraps(func) # 可以理解为记住原函数的属性
def wrapper(*args, **kw):
print("开始运行:{}".format(func.__name__))
print(args, kw)
func(*args, **kw)
print("结束运行:{}".format(func.__name__))
print(f"My name is :{name}".center(60, "-"))
return wrapper
return deco_iron
@deco_params("Yankerp")
def tony(*args, **kw):
print("my function name is:", tony.__name__)
def main():
tony('yankerp',80)
if __name__ == "__main__":
main()
>>>
开始运行:deco_iron......
开始运行:tony
('yankerp', 80) {}
my function name is: tony # tony
结束运行:tony
--------------------My name is :Yankerp---------------------
#!/usr/bin/env python
from functools import wraps
class DecoIron:
def __init__(self, name):
self.name = name
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kw):
print("hello world") # 输出一个hello world
print(*args, **kw)
func(*args, **kw) # 我们将用户传进来的函数进行返回 那么返回的这个函数 就是function
print(f"My name is:{self.name}".center(60, "-"))
return wrapper
@DecoIron('yankerp')
def tony(*args, **kw):
print("my function is:{}".format(tony.__name__))
if __name__ == "__main__":
tony('yankerp', 40)
>>>
hello world
yankerp 40
my function is:tony
---------------------My name is:yankerp---------------------
例1: 使用装饰器做一个日志输出
#!/usr/bin/env python
from functools import wraps
class Dlog:
def __init__(self, file_name):
self.file_mame = file_name
def __call__(self, func):
@wraps(func)
def warpper(*args, **kw):
str_log = "函数{}开始运行了....".format(func.__name__)
with open(self.file_mame, 'a', encoding='utf8') as f:
print(str_log)
f.write(str_log + '\n')
func(*args, **kw)
return warpper
@Dlog('yankerp.log')
def tony(*args, **kw):
print("my function is:{}".format(tony.__name__).center(60, "="))
if __name__ == "__main__":
tony()
> 函数tony开始运行了....
====================my function is:tony=====================
使用装饰器实现函数用时
#!/usr/bin/env python
import time
from functools import wraps
class Chatends:
def __init__(self, funcname=''):
self.funcname = funcname
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kw):
print("开始运行{}函数".format(func.__name__).center(60, "-"))
start_time = time.time()
func(*args, **kw)
result_time = time.time() - start_time
print(f"函数{func.__name__}运行结束,运行时间为:{int(result_time)}秒.....")
return wrapper
@Chatends()
def tony():
print("My function name is:{}".format(tony.__name__))
time.sleep(3)
@Chatends()
def tony2():
print("My function name is:{}".format(tony2.__name__))
time.sleep(5)
if __name__ == "__main__":
tony()
tony2()
>>>
-------------------------开始运行tony函数-------------------------
My function name is:tony
函数tony运行结束,运行时间为:3秒.....
------------------------开始运行tony2函数-------------------------
My function name is:tony2
函数tony2运行结束,运行时间为:5秒.....
多种功能操作
#!/usr/bin/env python
from functools import wraps
class Chatends:
def __init__(self, funcname, filename='yankerp.log'):
self.funcname = funcname
self.filename = filename
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kw):
if hasattr(self, self.funcname):
my_func = getattr(self, self.funcname)
if (my_func(func)):
func(*args, **kw)
return wrapper
def log(self, func):
str_log = "函数{}开始运行了....".format(func.__name__)
with open(self.filename, 'a', encoding='utf8') as f:
print(str_log)
f.write(str_log + '\n')
return True
def check(self, func):
str_log = "函数{}开始运行了....".format(func.__name__)
print(str_log)
user_name = input("user_name>>>")
user_password = input("user_password>>>")
if user_name == "yankerp" and user_password == "pwd123":
return True
else:
return False
@Chatends('check')
@Chatends('log')
def tony():
print("这是主功能函数...........".center(60, "="))
@Chatends('check')
@Chatends('log')
def tony2():
print("这是主功能函数222...........".center(60, "="))
if __name__ == "__main__":
tony()
tony2()