我成功地创建了一个装饰任何类型类的装饰器,为它们添加了一个标准接口,以便于访问,集成等......
我拒绝使用元类,因为关于这一点的文献说这是一种矫枉过正,大多数时候可以用类装饰器代替。困扰我的是以下几点:
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解释器的物理特性吗?
答案 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
调用Decoratorb)下一行的内容(类A的定义)用作包装函数的参数。在这个功能里面我: 1)记住初始类init以避免无限递归 2)定义一个新的init以在实例级别进行更改 3)为类绑定一个新的init方法 4)返回一个变换后的类对象
c)因为返回是一个类对象,每次实例化一个实例时,我都会直接进入init,因为这是它在新类中的绑定方式。