前言
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任务代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
常见装饰器:内置装饰器、类装饰器、函数装饰器、带参数的函数装饰器
实战
原始方法使用:
def use_logging(func_name):print("[debug] %s is running" %func_name )def bar():use_logging("bar")print("i am bar")def bar2():use_logging("bar2")print("i am bar2")bar()
bar2()
输出:
[debug] bar is running
i am bar
[debug] bar2 is running
i am bar2
函数装饰器古老的方式实现:
def use_logging(func):# print("[debug] %s is running" %func_name )def wrapper(*args, **kwargs):print("[debug] %s is running" % func.__name__)return func(*args, **kwargs)return wrapper()def bar():# use_logging("bar")print("i am bar")def bar2():# use_logging("bar2")print("i am bar2")bar = use_logging(bar)
bar2 = use_logging(bar2)
输出:
[debug] bar is running
i am bar
[debug] bar2 is running
i am bar2
这种方式比较麻烦,每次都要是要使用use_logging函数,所以进一步实现
函数装饰器实现:
def use_logging(func):# print("[debug] %s is running" %func_name )def wrapper(*args, **kwargs):print("[debug] %s is running" % func.__name__)return func(*args, **kwargs)return wrapper()@use_logging
def bar():# use_logging("bar")print("i am bar")@use_logging
def bar2():# use_logging("bar2")print("i am bar2")
输出:
[debug] bar is running
i am bar
[debug] bar2 is running
i am bar2
可以看到使用了@use_logging代替了bar = use_logging(bar),但是结果还是不变的。
带参数的函数装饰器:
def use_logging(level = "debug"):def decorator(func):def wrapper(*args, **kwargs):print("[%s] %s is running" % (level, func.__name__))return func(*args, **kwargs)return wrapper()return decorator@use_logging("info")
def bar():# use_logging("bar")print("i am bar")@use_logging("debug")
def bar2():# use_logging("bar2")print("i am bar2")
类装饰器的使用:
class Foo(object):def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print(" class decorator running")self.func()print(" class decorator ending")@Foo
def bar():print("i am bar")bar()
输出:
class decorator running
i am barclass decorator ending
内置装饰器使用:
class Student(object):def __init__(self,name,score):self.name = nameself.__score = score@propertydef score(self):return self.__score@score.setterdef score(self,score):if score < 0 or score > 100:raise ValueError("invalid score")self.__score = scores = Student("jarvis","100")
s.score = 99print(s.score)
输出:
99
修改 s.score = 101,此时输出报错
这里可以看到,内置装饰器的作用是可以判断修改的变量是否符合预期,不符合就报错