2015-09-25 58 views
0

在Python中,我使用了一个框架,让我挂接到一个生命周期,像这样:python mixin的方法不能被覆盖(默认)?

class MyView(BaseView): 
    def pre_save(self): 
     print "view presave" 

我想写一个mixin做一些pre_save,但我已经有很多的代码在大量的类如上所述使用pre_save,而不呼叫super()。如果我这样加入我的mixin:

class MyMixin(object): 
    def pre_save(self): 
     print "mixin presave" 

class MyView(MyMixin, BaseView): 
    def pre_save(self): 
     print "view presave" 

它自然地覆盖mixin,并仅打印“查看预置”。有没有另外一种偷偷摸摸的方式,我可以写MyMixin以不强制所有的客户意见记得打电话给super()

+1

不,没有别的方法,只能从所有'pre_save()'方法中调用'super()'。如果存在'BaseView.pre_save()'(并且什么也不做,甚至不调用'super()'),那么随处使用'super()'(mixin,具体视图)将确保所有调用都被正确链接。 –

+0

在平凡的编程错误上打桩“偷偷摸摸的方式”只会增加一些应该修复的问题。修正你的观点,以便他们正确地发出'超级'通话,从长远来看,它将为你节省更多的时间。 –

+0

@brunodesthuilliers我不认为“纯粹的编程错误”是准确的 - 以前没有混入,因此不需要调用super(),也不需要知道如何实现mixin以利用它。就这样,你可以不知不觉地在没有警告的情况下删除你的mixin的实现。 –

回答

1

这个答案是一个概念证明,而不是一个建议。 请勿在生产代码中执行此操作。您将创建维护噩梦。我同意那些评论你的问题,即唯一安全的方法是编辑派生类。

也就是说,技术上可以使用metaclass

def do_evil(self, method): 
    print "doing evil" 
    MyMixin.pre_save(self) 
    method(self) 

class ConcentratedEvil(type): 
    tainted_classes = ['MyView'] # Add others as needed 
    def __new__(mcs, name, bases, dict): 
     if name in mcs.tainted_classes: 
      print "tainting {0} with the power of evil".format(name) 
      old_method = dict['pre_save'] 
      dict['pre_save'] = lambda x: do_evil(x, old_method) 
      print dict.keys() 
     return type.__new__(mcs, name, bases, dict) 

class BaseView(object): 
    pass 

class MyMixin(object): 
    __metaclass__ = ConcentratedEvil 
    def pre_save(self): 
     print "mixin presave" 

class MyView(MyMixin, BaseView): 
    def pre_save(self): 
     print "view presave" 

此时你可以这样做:

>>> view = MyView() 
>>> view.pre_save() 
doing evil 
mixin presave 
view presave 
>>> 

我认为这仅仅在进行MyMixin是在基类列表的前面。

+0

Neato。想想我可以自动地污染所有使用'MyMixin'的类,而不是维护'tainted_classes'列表? –

+0

嗯。大概。我敢打赌,你可以搜索“MyMixin”的基础列表。我不确定如果你的课程在不同的模块中它将如何工作。您可能需要检查合格和不合格的名称。 –