我试图寻找创建一个类的装饰,做以下的最佳方式:
- 注入的一些功能到装饰类
- 迫使这些函数的调用装饰类AFTER
__init__
被称为
目前,我只是保存关闭的“原始”的引用__init__
方法和我的替换它__init__
调用原来和我的附加功能。 它看起来类似于这样:
orig_init = cls.__init__
def new_init(self, *args, **kwargs):
"""
'Extend' wrapped class' __init__ so we can attach to all signals
automatically
"""
orig_init(self, *args, **kwargs)
self._debugSignals()
cls.__init__ = new_init
是否有“扩充”原来更好的方法__init__
或注入我别的地方打电话? 我真正需要的是我的self._debugSignals()
某个时候在创建对象后调用。 我也希望它会自动发生,这就是为什么我认为后__init__
是个好地方。
额外的杂项。 装饰注意事项
这可能是值得一提的这个装饰的一些背景。 你可以找到完整的代码在这里 。 装饰器的点是它们被发射时自动附加到任何PyQt的信号并打印。 当我装点自己的子类的装饰工作正常QtCore.QObject
,但最近我一直在试图自动装饰QObject的所有儿童 。
我想有一个“调试”模式的应用程序,我可以自动打印所有信号只是为了确保事情在做什么我的期望。 我敢肯定,这将导致调试万吨,但我还是想看看发生了什么。
问题是我目前装饰的版本,导致更换时,段错误QtCore.QObject.__init__
。 我试着调试这一点,但代码生成的所有SIP,我没有用太多的经验。
所以,我想知道是否有注入一个函数调用后一个更安全,更Python的方式__init__
,并希望避免段错误。
基于这个职位和这个答案 ,用另一种方式做,这是通过自定义的元类 。 这将表现为如下(在Python 2.7测试):
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the __metaclass__ set as our custom metaclass
class MyNewClass(object):
__metaclass__ = NewInitCaller
def __init__(self):
print "Init class"
def new_init(self):
print "New init!!"
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!
其基本思想是:
当你调用MyNewClass()
它会搜索元类,找到了已定义NewInitCaller
元类__call__
函数被调用。
这个函数创建MyNewClass
使用实例type
,
实例运行其自己的__init__
(打印“初始化类”)。
然后,元类调用new_init
实例的功能。
下面是Python的3.x的解决方案的基础上, 这个帖子的接受的答案 。 另请参阅PEP 3115参考,我认为理由是一个有趣的阅读。
在以上示出带注释的示例的变化; 唯一真正的变化是元类的定义方式,所有其他的是微不足道的2to3的修改。
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the metaclass passed as an argument
class MyNewClass(object, metaclass=NewInitCaller): # added argument
# __metaclass__ = NewInitCaller this line is removed; would not have effect
def __init__(self):
print("Init class") # function, not command
def new_init(self):
print("New init!!") # function, not command
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!