文章目录
- 函数装饰器
- 基础装饰器
- 查看函数信息
- 装饰器带开关
- 类装饰器
- 装饰类中的函数
- 装饰普通函数
- 常用内置装饰器
- property -- 方法转属性
- classmethod - 类绑定方法
- staticmethod - 类和对象都可以调用
- 多个装饰器执行顺序
函数装饰器
基础装饰器
"""
每个装饰器完成一个独立的功能, 功能之间互相分离
可以装饰普通函数
也可以装饰类中的函数
"""
def wrap1(func):
def inner(*args, **kwargs):
print("wrap1 option")
r = func(*args, **kwargs)
return r
return inner
# 装饰普通函数
@wrap1
def sum(x, y):
return x+y
# 装饰类中的函数
class Foo:
@wrap1
def sum(x, y):
return x+y
print(sum(1, 2))
print(Foo().sum(1, 2))
查看函数信息
# 需要查看函数内部信息, 导入下边这个包
from functools import wraps
def wrap2(func):
@wraps(func)
def inner(*args, **kwargs):
print("wrap2 option")
r = func(*args, **kwargs)
return r
return inner
@warp2
def sum(x, y):
"""
求和函数
"""
return x+y
print(func_a.__doc__) # 此时可以拿到内部信息
装饰器带开关
"""
声明一个 tag, 在函数定义时传给装饰器
通常有两种用法
1. 用作总开关, 参数为变量, 因为当参数为变量时, 声明函数时即确定装饰器的参数, 并非调用前可改
2. 仅少量函数需要装饰器, 参数为定值
"""
from functools import wraps
wrap_tag = True
def wrap3(tag):
def outer(func):
@wraps(func)
def inner(*args, **kwargs):
print(tag)
if tag:
print("wrap3 option")
r = func(*args, **kwargs)
return r
return inner
return outer
# 定义函数时, tag已经保存, 而不是函数调用时再查找这个 tag 的值
@wrap3(wrap_tag) # 此时 wrap_tag 为 True, 所以后续执行的 sum 方法, 都会执行装饰器中操作
def sum(x, y):
"""
求和函数
"""
return x+y
print(sum(1, 2))
# 即使这里修改 tag 为 False, 函数仍旧会执行装饰器中操作
wrap_tag = False
print(sum(1, 2))
类装饰器
装饰类中的函数
class Wrap:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
print("执行装饰器代码")
r = lambda *args, **kwargs: self.func(instance, *args, **kwargs)
return r
class Foo:
@Wrap
def sum(self, x, y):
return x+y
print(Foo().sum(1, 2))
装饰普通函数
class Wrap:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("执行装饰器代码")
r = self.func(*args, **kwargs)
return r
@Wrap
def sum(x, y):
return x+y
print(sum(1, 2))
常用内置装饰器
property – 方法转属性
"""
类中方法的调用是 obj.funcName()
但有时候, 这样的使用并不符合"属性"和"方法"的使用习惯
例如: 直径属于圆的属性
我们使用它的时候, 用属性的方式更加合理
"""
class Circle:
def __init__(self, r):
self.r = r
# 将 "调用方法" 转换为 "获取属性"
@property
def d(self):
return self.r * 2
# 实例化一个半径为 1 的 Circle
c = Circle(1)
print(c.d)
classmethod - 类绑定方法
class Foo:
# 将方法绑定为类方法, 使其可以不通过对象即可调用, 参数 cls 为类本身
@classmethod
def boo(cls):
print("我是 %s 类" % cls.__name__)
# 直接使用 className.funcName() 调用
Foo.boo()
staticmethod - 类和对象都可以调用
class Foo:
@staticmethod
def check_err(err):
if err != None:
print(err)
# 可以通过 class.funcName 调用
Foo.check_err("输入有误")
# 也可以实例化后, 通过 obj.funcName 调用
f = Foo()
f.check_err("输入有误")
多个装饰器执行顺序
"""
多个装饰器同时装饰一个函数时, 按装饰先后顺序依次执行
并遵循先入后出的规则
所以下边示例的结果为:
1 start
2 start
func
2 end
1 end
"""
def wrapper1(func):
def inner(*args, **kwargs):
print("1, before")
func(*args, **kwargs)
print("1, end")
return inner
def wrapper2(func):
def inner(*args, **kwargs):
print("2, before")
func(*args, **kwargs)
print("2, end")
return inner
# 同一个函数需要两个或两个以上额外的功能
@wrapper1
@wrapper2
def funcA(x):
print(x)
funcA(100)