Python中关于类装饰器的使用问题请教

1、下面是第一个类装饰器

def decorator(cls):

    class Wrapper:
def __init__(self, *args):  
	self.wrapped = cls(*args)

def __getattr__(self, name):  
	return getattr(self.wrapped, name)

return Wrapper

[@decorator](/user/decorator)

class C:

    def __init__(self, x, y):  
self.attr = 'spam'

2、下面是第二个类装饰器

class Decorator:

    def __init__(self, C): 
	self.C = C
def __call__(self, *args): 
self.wrapped = self.C(*args)
return self

def __getattr__(self, attrname): 
return getattr(self.wrapped, attrname)

[@Decorator](/user/Decorator)

class C: ...

我看到书上说,第二个类装饰器和第一个不同,第二个没有能够处理给定的类的多个实例——每个实例创建调用都覆盖了前面保存的实例。第一个类装饰器却支持多个实例,因为每个实例创建调用产生了一个新的独立的包装器对象。

请问怎么理解上面这段话,为何第二个类装饰器在每个实例创建时都会覆盖前面保存的实例呢? 感谢指点!


Python中关于类装饰器的使用问题请教

8 回复

去看描述器 看完再回来看你的问题


在Python里,类装饰器本质上是一个可调用对象(通常是函数或类),它接收一个类作为参数,并返回一个修改后的类(或一个完全不同的类)。最常见的用法是用一个函数包裹目标类,在函数内部修改或增强类的行为,然后返回这个类。

一个最直接的模式是写一个接收cls参数的函数,在函数内部动态修改类(比如添加、修改方法或属性),最后返回修改后的类。下面是一个给类添加新方法的完整例子:

def add_method_to_class(cls):
    """类装饰器:给类动态添加一个实例方法"""
    def new_method(self):
        return f"{self.__class__.__name__} called new_method"
    # 将新方法绑定到类上
    cls.new_method = new_method
    return cls

@add_method_to_class
class MyClass:
    def original_method(self):
        return "original"

obj = MyClass()
print(obj.original_method())  # 输出: original
print(obj.new_method())       # 输出: MyClass called new_method

更复杂一点,你可以用类来实现装饰器。这种类需要实现__init____call__方法,__init__接收被装饰的类,__call__在类被实例化时介入。下面是一个用类实现的装饰器,它拦截实例创建并打印日志:

class LogInstances:
    """类装饰器(用类实现):记录类的实例化"""
    def __init__(self, cls):
        self.cls = cls
        self.instance_count = 0

    def __call__(self, *args, **kwargs):
        self.instance_count += 1
        print(f"Creating instance {self.instance_count} of {self.cls.__name__}")
        return self.cls(*args, **kwargs)

@LogInstances
class MyClass:
    pass

obj1 = MyClass()  # 输出: Creating instance 1 of MyClass
obj2 = MyClass()  # 输出: Creating instance 2 of MyClass

类装饰器的一个强大用途是自动注册子类。比如在Web框架中,常用类装饰器将视图类注册到路由系统:

_registry = []

def register_view(cls):
    """类装饰器:自动注册视图类"""
    _registry.append(cls)
    return cls

@register_view
class HomeView:
    pass

@register_view
class UserView:
    pass

print(_registry)  # 输出: [<class '__main__.HomeView'>, <class '__main__.UserView'>]

核心要点: 类装饰器就是修改或包装类的函数或类。

哦理解错,我以为是类里面的装饰器 ,你这是装饰类的装饰器

这不很简单么第二个类装饰器可以预接参数成为实例,然后装饰类的时候是这个实例的 call 方法去套

第一个是相当于把这个装饰器类实例化,初始化参数就是一个类


装饰器就是套娃语法糖 func(func(func()))

自己套一下就知道了

谢谢,你写得话我基本能看明白,但是我还是无法和我的问题联系起来理解,第二个类装饰器是调用 Decorator.__call__方法,可这和“没有能够处理给定的类的多个实例——每个实例创建调用都覆盖了前面保存的实例”这句话有什么关系?

我不知道要怎么理解这句话“没有能够处理给定的类的多个实例——每个实例创建调用都覆盖了前面保存的实例。” ,覆盖?怎么个覆盖法?

因为只是在调用一个 global 的 functor instance (

您是说 self.C 是从外部传入的参数,所以可以看做是 global 的实例化方法,但是 cls 就是作用域在 wrapper 定义域内的实例化方法么?

关于这个问题,我另外又发了个帖子,我觉得好像找到了存在矛盾的例子,能否指点,感谢!
https://www.v2ex.com/t/384994#reply0

回到顶部