在Python中使用MixIns的优雅方法是什么?

Sla*_*a V 7 python mixins

我需要找到一种优雅的方式来做两种MixIns.

第一:

class A(object):
    def method1(self):
        do_something()
Run Code Online (Sandbox Code Playgroud)

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

第二:

class B(object):
    def method1(self):
        do_something()
        do_more()
Run Code Online (Sandbox Code Playgroud)

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

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

Fisrt one通过使用self._old_method1 = self.method1(); self.method1() = self._new_method1();和写入_new_method1()调用_old_method1().

问题:多个MixIns都将重命名为_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
Run Code Online (Sandbox Code Playgroud)

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


第二个解决方案如下,用"pass_func"替换lambda:0.

Bol*_*wyn 5

我认为,这可以使用装饰器以相当Pythonic的方式处理.(PEP 318也是)


unu*_*tbu 3

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

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

__old_method1在和中使用双下划线__method1非常有用MixInClass1。由于 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()
Run Code Online (Sandbox Code Playgroud)