装修班装修一次就忘了吗?

2024-04-24 17:00:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我成功地创建了一个装饰器来装饰任何类型的类,并为它们添加了一个标准接口,以便于访问、集成等。。。在

我一直反对使用元类,因为在这一点上的文献认为这是一种过度使用,而且大多数时候可以被类装饰器所取代。让我烦恼的是:

def Decorator(somearg):

    def wrapper(cls):
        clsinit = cls.__init__
        cls.members = []

        def __init__(self, *args, **kwargs):
            #do something with somearg...
            self.__class__.members.append(self)
            clsinit(self,*args,**kwargs)

        cls.__init__ = clsinit
        return cls

    return wrapper

@Decorator('thearg')
class A(object):
    pass

a = A()
b = A()

使用python调试器,在导入时,类A立即用参数“thearg”修饰。但是每次实例化A()时,实例都直接调用decorator中定义的init,而不经过前面的层。这很好,因为我希望我的类记录每个成员,而不是每次实例化新实例时都重置。但我不知道为什么。在

有人能解释一下python解释器在这个特殊情况下的物理原理吗?在


Tags: 实例selfreturninitdefargs装饰decorator
3条回答

如果只是更改类而不是创建新类,则不需要包装器函数(应该是包装器类):

def Decorator(cls):
    clsinit = cls.__init__
    cls.members = []

    def __init__(self, *args, **kwargs):
        clsinit(self, *args, **kwargs)
        self.__class__.members.append(self)

    cls.__init__ = __init__
    return cls

顺便说一句,您应该创建一个基类并从中继承:

^{pr2}$

干净多了

更新后的问题,请参考您的代码:

"But each time I instantiate A(), the instance calls straight to the init defined in the decorator, without passing through the previous layers."

它这样做是因为当Decorator()函数创建的wrapper()类修饰符函数应用于class A时,它用自己动态定义的wrapper.__init__()替换了{}的{}。每当As被实例化时,函数就是被调用的函数,它首先被写出来做一些事情,然后在最后调用原始的A.__init__()。在

感谢@JBernardo和@martineau的回答。我使用这段代码的目的是实现类对象的类似容器的行为,以便更容易地访问它们的实例。但是我想一次访问一个与每个类相关的实例,而不是所有实例都在同一个继承类中。在

实际上,再次编写代码有助于我理解我的问题:

a)Decorator的参数为somearg

b)下一行的内容(类A的定义)用作包装器函数的参数。在这个函数中我: 1) 记住初始类init以避免无限递归 2) 定义一个新的init以在实例级别进行更改 3) 为类绑定一个新的init方法 4) 返回转换后的类对象

c)因为返回是一个类对象,所以每次实例化一个实例时,我都直接转到init,因为这就是它在新类中的绑定方式。在

相关问题 更多 >