文章目录

  • 函数装饰器
  • 基础装饰器
  • 查看函数信息
  • 装饰器带开关
  • 类装饰器
  • 装饰类中的函数
  • 装饰普通函数
  • 常用内置装饰器
  • 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)