装饰一个类 - 装饰一旦忘记它?

时间:2013-02-09 02:58:41

标签: python decorator interpreter

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

我拒绝使用元类,因为关于这一点的文献说这是一种矫枉过正,大多数时候可以用类装饰器代替。困扰我的是以下几点:

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()时,实例都会直接调用装饰器中定义的init,而不会通过前面的层。这很好,因为我希望我的类记录每个成员,而不是每次实例化新实例时都重置。但我不确定我理解为什么。

有人可以解释这个特定情况下python解释器的物理特性吗?

3 个答案:

答案 0 :(得分:2)

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

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
顺便说一句,你应该创建一个基类并从中继承:

class Base(object):
    members = []
    def __init__(self):
        self.__class__.members.append(self)

class A(Base):
    pass

更清洁

答案 1 :(得分:0)

好的,请参考更新后的问题中的更正后的代码:

  

“但每次我实例化A()时,实例都直接调用   init在装饰器中定义,不经过前一个   层“。

这样做是因为当wrapper()函数创建的Decorator()类装饰器函数应用于class A时,它会替换A的{​​{1}}具有自己动态定义的__init__()函数。 那个函数是在实例化wrapper.__init__()时被调用的函数,它首先编写一些东西,然后在最后调用原始的A

答案 2 :(得分:0)

感谢@JBernardo和@martineau的回答。我对此代码的目标是实现容器类对象的行为,以便更容易地到达它们的实例。但我希望一次访问一个相对于每个类的实例,而不是所有在同一继承类中的实例。

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

a)使用其参数somearg

调用Decorator

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

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