在Python中优雅地实现MixIns的方法有哪些?
我需要找到一种优雅的方法来实现两种 MixIn。
第一种:
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()
。
问题是:多个 MixIn 都会重命名为 _old_method1,这样就显得不优雅了。
第二个 MixIn 的问题是通过创建一个虚拟方法 call_mixin(self): pass
来解决的,并在调用之间插入它,定义 self.call_mixin()
。同样,这也不优雅,并且在多个 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 个回答
这里有另一种实现 MixinClass1
和 MixinClass2
的方法:
装饰器在你需要包装很多函数的时候很有用。不过因为 MixinClass1
只需要包装一个函数,我觉得用猴子补丁(monkey-patch)会更清晰:
在 MixinClass1
中使用双下划线来命名 __old_method1
和 __method1
是很有用的。因为 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()