与装饰__init__后注入功能调用(Injecting function call after _

2019-08-31 06:40发布

我试图寻找创建一个类的装饰,做以下的最佳方式:

  1. 注入的一些功能到装饰类
  2. 迫使这些函数的调用装饰类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__ ,并希望避免段错误。

Answer 1:

基于这个职位和这个答案 ,用另一种方式做,这是通过自定义的元类 。 这将表现为如下(在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!!

其基本思想是:

  1. 当你调用MyNewClass()它会搜索元类,找到了已定义NewInitCaller

  2. 元类__call__函数被调用。

  3. 这个函数创建MyNewClass使用实例type

  4. 实例运行其自己的__init__ (打印“初始化类”)。

  5. 然后,元类调用new_init实例的功能。



Answer 2:

下面是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!!


文章来源: Injecting function call after __init__ with decorator