1

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

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

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 解释器的物理特性吗?

4

3 回答 3

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

更清洁

于 2013-02-09T04:01:05.560 回答
0

好的,参考更新问题中的更正代码,您会问:

“但每次我实例化 A() 时,实例都会直接调用装饰器中定义的 init,而不会通过前面的层。”

这样做是因为当wrapper()函数创建的类装饰器函数Decorator()应用于 时,它会用自己的动态定义函数class A替换A's 。每当实例化 s时都会调用函数,并且首先编写它做一些事情,然后在最后调用原始函数。__init__()wrapper.__init__()AA.__init__()

于 2013-02-09T04:33:40.453 回答
0

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

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

a)装饰器被调用,其参数为 somearg

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

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

于 2013-02-09T10:02:39.373 回答