代码之家  ›  专栏  ›  技术社区  ›  Slava V

在Python中进行混合的优雅方法是什么?

  •  7
  • Slava V  · 技术社区  · 15 年前

    我需要找到一个优雅的方式做两种混合。

    第一:

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

    现在,A MixInClass 应该做 method1 这样做: do_other() -gt; A.method1() -gt; do_smth_else() -也就是说,基本上“包装”旧功能。我很确定一定有一个很好的解决办法。

    第二:

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

    在这种情况下,我想 MixInClass2 能够在 do_something() do_more() ,即: dothOnththIn() -gt; MixIn.method1 -gt; doiMuor() . 我知道这可能需要修改 class B -没关系,只是想找到最简单的方法来实现这一点。

    这些都是很小的问题,我确实解决了,但我的解决方案被污染了。

    通过使用 self._old_method1 = self.method1(); self.method1() = self._new_method1(); 写作 _new_method1() 呼唤 _old_method1() .

    问题:多个mixin都将重命名为\u old\u method1,并且不美观。

    通过创建一个虚拟方法来求解第二个混合1。 call_mixin(self): pass 在调用和定义之间注入 self.call_mixin() . 再次不雅,将打破多个混合。

    有什么想法吗?


    多亏了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 .

    2 回复  |  直到 15 年前
        1
  •  3
  •   unutbu    15 年前

    下面是实现mixinclass1、mixinclass2的另一种方法:

    当需要包装许多函数时,装饰器很有用。自从 MixinClass1 只需要包装一个功能,我觉得猴子补丁更清楚:

    使用双下划线 __old_method1 __method1 MixInClass1 . 由于python的名称管理约定,使用双下划线将这些属性本地化为 混合类1 并且允许您对类中的其他混合使用非常相同的属性名,而不会导致不需要的名称冲突。

    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()
    
        2
  •  5
  •   Boldewyn    15 年前

    我想,这可以用相当多的方法来处理 decorators . ( PEP 318 也一样)