hi, 大家新年好,已经有很长一段时间没有分享自己的 python 方面的技术,这次分享下自己总结的 python 装饰器方面,主要有以下几点:
定义
作用
函数装饰器:函数实际被调用的时候会直接返回一个由函数装饰器包装好的函数对象进行回调, 可以修饰在函数或定义的类方法
编写基本的函数装饰器
- def decorator_fn(call_fn):
- if auth(): u"""
- 如果是授权成功则直接调用函数
- """
- return call_fn # 没有权限,不执行函数,返回一个包装None的可调用对象
- return callable(None) @decorator_fndef call_fn():
- print("call fn ...")# 上述的call_fn对象等价于call_fn = decorator_fn(call_fn)# 之后再根据参数进行调用call_fn() # 此时该函数已增加授权校验功能
类装饰器:类实际被调用的时候会直接返回一个由函数装饰器包装好的类进行回调, 让该类具有某种属性或行为
- def decorator(aClass):
- print("intercept ....") return aClass @decoratorclass Person(object):
- pass
注意上述使用装饰器修饰的 Person 已经是调用装饰器函数并返回 Person 对象,即定义类的时候已经拥有装饰器的功能,因此不论如何调用 Person() 创建实例,上面仅会打印一次 interceptPerson() 分两步:
执行包装的 intercept 然后返回原 Person 类,也就是获取到的 Person 已经调用过装饰器里面的方法
- Person = decorator(Person)
函数装饰器嵌套
- @fn1@fn2@fn3def fn(*args, **kwargs):
- pass# fn对象等价于fn = fn1(fn2(fn3(fn)))
类装饰器嵌套
- @fn1@fn2@fn3class Person(object):
- pass# 上述定义的类Person已经是具有fn1,fn2,fn3的所有装饰器功能Person = fn1(fn2(fn3(Person)))
修饰带有参数的函数的装饰器, 这时候装饰器的作用就是返回一个函数的代理
- def decorator(fn):
- def proxy(*args, **kwargs):
- u"""
- 作为代理函数来调用原有的函数,并对原来的函数进行auth的校验
- :param args:
- :param kwargs:
- :return:
- """
- print("auth checking") return fn(*args, **kwargs) return proxy @decoratordef fn(a=9, b=10):
- print(a+b)
上述的被装饰器修饰的 fn 等价于 proxy,在函数 proxy 中已经保存了 fn 函数的对象因此调用 fn() 就等价于调用 proxy(), 而 proxy() 函数增加了 auth 认证校验,即:
再进一步拆分,即: fn = decorator(fn)
- fn(*args, **kwargs) = decorator(fn)(*args, **kwargs)
修饰带有参数初始化类的装饰器
- def decorator(aClass):
- def proxy(*args, **kwargs):
- u"""
- 作为代理函数来调用原有的函数,并对原来的函数进行auth的校验
- :param args:
- :param kwargs:
- :return:
- """
- print("auth checking") return aClass(*args, **kwargs) return proxy @decoratorclass Person(object):
- def __call__(self, *args, **kwargs):
- print("person ...")
注意体会与上述定义类装饰器的区别, 这个时候定义的 Person 并非 Person 类,而是一个定义在 decorator 函数内部的一个代理函数,这个代理函数保存了 aClass 这个类对象,即:
,进一步拆分,即:
- Person(*args, **kwargs) = decorator(Person)(*args, **kwargs)
- Person = decorator(Person)
定义的装饰器函数传递参数
- def decorator(cache_time, strategy):
- def actual_decorator(fn):
- print("using cache_time[%s] and strategy[%s] do the first job" % (cache_time, strategy)) def proxy(*args, **kwargs):
- print("before call must be do the second job..")
- fn(*args, **kwargs) return proxy return actual_decorator @decorator(cache_time=10, strategy="")def call_fn(a, b=10):
- if a < b:
- print("a < b") elif a > b:
- print("a > b") else:
- print("a = b") # 使用上述的装饰器修饰的call_fn等价于# call_fn = decorator(cache_time=10, strategy="")(call_fn) # 调用了两次函数,最终返回代理proxyclass Person(object): @decorator(cache_time=10, strategy="nio")
- def cal(self,a, b=10):
- if a < b:
- print("a < b") elif a > b:
- print("a > b") else:
- print("a = b") # 同理,定义的cal函数等价于# cal = decorator(cache_time=10, strategy="nio")(cal) # 调用了两次函数并返回代理函数
使用装饰器要分清楚以下几点:
来源: https://juejin.im/entry/5a48a507f265da430d585b89