7

我需要找到一种优雅的方式来做 2 种 MixIn。

第一的:

class A(object):
    def method1(self):
        do_something()

现在,aMixInClass应该method1这样做:do_other()-> A.method1()-> do_smth_else()- 即基本上“包装”旧函数。我很确定必须有一个很好的解决方案。

第二:

class B(object):
    def method1(self):
        do_something()
        do_more()

在这种情况下,我希望MixInClass2能够在do_something()and之间注入自身do_more(),即:do_something()-> MixIn.method1-> do_more()。我知道这可能需要修改class B- 没关系,只是寻找最简单的方法来实现这一点。

这些都是非常微不足道的问题,我实际上解决了它们,但我的解决方案被污染了。

第一个使用self._old_method1 = self.method1(); self.method1() = self._new_method1();和编写_new_method1()调用_old_method1().

问题:多个 MixIn 将全部重命名为 _old_method1 并且不优雅。

第二个 MixIn 是通过创建一个虚拟方法call_mixin(self): pass并在调用和定义之间注入它来解决的self.call_mixin()。再次不优雅并且会在多个 MixIns 上中断..

有任何想法吗?


感谢 Boldewyn,我为第一个找到了优雅的解决方案(我忘记了您可以即时创建装饰器,而无需修改原始代码):

class MixIn_for_1(object):
    def __init__(self):
        self.method1 = self.wrap1(self.method1)
        super(MixIn_for_1, self).__init__()

    def wrap1(self, old):
        def method1():
            print "do_other()"
            old()
            print "do_smth_else()"
        return method1

仍在寻找第二个想法(这个想法不适合,因为我需要在旧方法内部注入,而不是在外部注入,就像在这种情况下一样)。


第二个解决方案如下,将“pass_func”替换为lambda:0.

4

2 回答 2

5

我认为,这可以使用decorators以一种 Pythonic 的方式来处理。(PEP 318也是)

于 2010-05-03T10:30:53.817 回答
3

下面是实现 MixInClass1、MixinClass2 的另一种方式:

当您需要包装许多函数时,装饰器很有用。由于MixinClass1只需要包装一个函数,我认为猴子补丁更清楚:

使用双下划线__old_method1__method1MixInClass1. 由于 Python 的名称修改约定,使用双下划线将这些属性本地化,MixinClass1并允许您对其他混合类使用完全相同的属性名称,而不会导致不必要的名称冲突。

class MixInClass1(object):
    def __init__(self):
        self.__old_method1,self.method1=self.method1,self.__method1
        super(MixInClass1, self).__init__()        
    def __method1(self):
        print "pre1()"
        self.__old_method1()
        print "post1()"

class MixInClass2(object):
    def __init__(self):
        super(MixInClass2, self).__init__()        
    def method1_hook(self):
        print('MixIn method1')

class Foo(MixInClass2,MixInClass1):
    def method1(self):
        print "do_something()"
        getattr(self,'method1_hook',lambda *args,**kw: None)()
        print "do_more()"

foo=Foo()
foo.method1()
于 2010-05-03T14:10:13.047 回答