装饰器基础二装饰类的装饰器

类可以做装饰器,也可以被装饰器装饰,被装饰器装饰,那这个装饰器可以接收一个类,返回一个类

1、装饰类的装饰器-输入类返回类

def add_str(cls):
    def __str__(self):
        return str(self.__dict__)

    cls.__str__ = __str__
    return cls


@add_str
class MyObject:
    def __init__(self, a, b):
        self.a = a
        self.b = b


# 等价形式 MyObject = add_str(MyObject)
o = MyObject(1, 2)
print(type(o))
print(o)

2、先实现普通函数装饰器

def log_func(func):
    def wrapper(*args, **kwargs):
        print('func start!')
        print(f'args: {args}')
        res = func(*args, **kwargs)
        print('func end!')
        return res
    return wrapper


@log_func
def fib(n):
    if n <= 1:
        return 0
    return fib(n - 1) + fib(n - 2)

# print(fib(3))

2.1、普通函数装饰器用类包起来, 直接实例化类调用装饰器

class Decorator:
    def log_func(self, func):
        def wrapper(*args, **kwargs):
            print('func start!')
            print(f'args: {args}')
            res = func(*args, **kwargs)
            print('func end!')
            return res

        return wrapper


d = Decorator()


@d.log_func
def fib(n):
    if n <= 1:
        return 0
    return fib(n - 1) + fib(n - 2)


print(fib(4))

2.2、使用类方法装饰器

class Decorator:
    @classmethod
    def log_func(cls, func):
        def wrapper(*args, **kwargs):
            print('func start!')
            print(f'args: {args}')
            res = func(*args, **kwargs)
            print('func end!')
            return res

        return wrapper


@Decorator.log_func
def fib(n):
    if n <= 1:
        return 0
    return fib(n - 1) + fib(n - 2)


print(fib(4))

2.3、使用静态方法装饰器

class Decorator:
    @staticmethod
    def log_func(func):
        def wrapper(*args, **kwargs):
            print('func start!')
            print(f'args: {args}')
            res = func(*args, **kwargs)
            print('func end!')
            return res

        return wrapper


@Decorator.log_func
def fib(n):
    if n <= 1:
        return 0
    return fib(n - 1) + fib(n - 2)


print(fib(4))

总结:上面实现的是类装饰器给外部函数调用,内部的装饰器函数可以是静态方法,类方法,或者实例方法,那类内部这个装饰器可以给类内部实例方法使用吗?
答案是可以,但是需要像下面这么写。

3、给类方法使用的类装饰器

class Decorator:
    # @staticmethod
    def log_func(func):
        def wrapper(*args, **kwargs):
            print('func start!')
            print(f'args: {args}')
            res = func(*args, **kwargs)
            print('func end!')
            return res

        return wrapper

    @log_func
    def fib(self, n):
        if n <= 1:
            return 0
        return fib(n - 1) + fib(n - 2)


d = Decorator()
print(d.fib(4))
print('结束')

此时装饰器方法不是实例方法,类方法,静态方法,此时他可以说是类辅助函数装饰器,内部调用没有问题。
但是外部调用就出问题了~

# 外部调用
d = Decorator()
@d.log_func
def f():  # 会报TypeError
    pass

外部调用会报TypeError,参数异常。 外部调用时解释器会把类中log_func这个辅助函数当成一个正常实例方法解读,而这个方法中缺少了self,而使用Decorator类的方式外部直接调用则不会报错。此时外部应该使用类直接调用。


@Decorator.log_func
def f():  # 正常输出
    pass

4、哪有没有在类中或外部不管通过实例还是类方法均可调用呢,有的,需要在最后一行加如下代码: log_func = staticmethod(log_func) 或者在函数使用@staticmethod修饰成静态方法

class Decorator:
    # @staticmethod
    def log_func(func):
        def wrapper(*args, **kwargs):
            print('func start!')
            print(f'args: {args}')
            res = func(*args, **kwargs)
            print('func end!')
            return res

        return wrapper

    @log_func
    def fib(self, n):
        if n <= 1:
            return 0
        return fib(n - 1) + fib(n - 2)

    log_func = staticmethod(log_func)


# 内部调用
d = Decorator()
print(d.fib(4))

# 对象实例调用
d = Decorator()

@d.log_func
def f():  # 会报TypeError
    pass

# 类调用
@Decorator.log_func
def g():  # 正常输出
    pass

posted @   鱼的记忆·  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示