2010-05-03 51 views
7

我需要找到一种优雅的方式来做2种MixIns。在Python中执行MixIns的优雅方法有哪些?

第一:

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

现在,MixInClass应该method1做到这一点:do_other() - >A.method1() - >do_smth_else() - 即基本上是 “包裹” 老功能。我很确定这一定有一个很好的解决方案。

二:

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

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

这些都是非常微不足道的问题,我真的解决了它们,但我的解决方案受到了污染。

通过使用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 

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


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

+0

为了您的第二个问题,确实需要mixin.method1参数,如果是的话,做这些参数取决于变量/返回值在do_something()?最后,do_more()需要你的mixin的结果吗? – KillianDS 2010-05-03 11:35:57

+0

不,do_more()不需要结果。参数?我可能只需要“自我”,无论如何都应该通过。 – 2010-05-03 13:29:20

回答

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() 
+0

第一种解决方案与我所描述的完全相同。 第二个是聪明的,假设'Foo'是'B'并且pass_func是'lambda:0'。 – 2010-05-03 15:47:24

+0

@Slava:如果您使用'pass_func',那么如果您稍后决定将参数传递给'method1_hook',则不必更改'Foo'。如果你使用'lambda:0',那么你将不得不将它改变为'lambda x,y,z:0'。 – unutbu 2010-05-03 16:47:25

+0

1.什么是'pass_func'? 2.我们不能只做'lambda * args,** kwargs:0'吗? – 2010-05-03 18:24:37

5

我认为,可以使用decorators以相当的Pythonic方式处理。 (PEP 318,太)

+0

谢谢,这解决了我的第一个问题。我确实想到了装饰器,但我忘记了我可以用deco(方法)构造装饰器,而不是@deco。后者需要修改原始代码。 – 2010-05-03 11:07:10

相关问题