在python中,即使子类重写它,如何确保始终调用我的类的方法之一?

时间:2011-11-01 17:16:43

标签: python subclass

例如,我有一个

class BaseHandler(object):
    def prepare(self):
        self.prepped = 1

我不希望每个人都是BaseHandler的子类,也想要实现准备必须记住调用

super(SubBaseHandler, self).prepare()

有没有办法确保运行超类方法,即使子类也实现了prepare?

5 个答案:

答案 0 :(得分:14)

我使用元类解决了这个问题。

使用元类允许BaseHandler的实现者确保所有子类都将调用超类prepare()而不调整任何现有代码。

元类在两个类上查找prepare的实现,然后用调用superclass.prepare后跟subclass.prepare的子类覆盖子类prepare。

class MetaHandler(type):
    def __new__(cls, name, bases, attrs):
        instance = type.__new__(cls, name, bases, attrs)
        super_instance = super(instance, instance)
        if hasattr(super_instance, 'prepare') and hasattr(instance, 'prepare'):
            super_prepare = getattr(super_instance, 'prepare')
            sub_prepare = getattr(instance, 'prepare')
            def new_prepare(self):
                super_prepare(self)
                sub_prepare(self)
            setattr(instance, 'prepare', new_prepare)
        return instance


class BaseHandler(object):
    __metaclass__ = MetaHandler
    def prepare(self):
        print 'BaseHandler.prepare'


class SubHandler(BaseHandler):
    def prepare(self):
        print 'SubHandler.prepare'

使用它看起来像这样:

>>> sh = SubHandler()
>>> sh.prepare()
BaseHandler.prepare
SubHandler.prepare

答案 1 :(得分:4)

告诉开发人员定义prepare_hook而不是prepare,但是 告诉用户致电prepare

class BaseHandler(object):
    def prepare(self):
        self.prepped = 1
        self.prepare_hook()
    def prepare_hook(self):
        pass

class SubBaseHandler(BaseHandler):
    def prepare_hook(self):
        pass

foo = SubBaseHandler()
foo.prepare()

如果您希望从多个子类进行更复杂的prepare调用链接,那么您的开发人员应该真正使用super这就是它的目的。

答案 2 :(得分:3)

接受你必须告诉人们继承你的类,以便在覆盖它时调用基本方法。其他每一个解决方案都要求你解释它们做其他事情,或者涉及一些可能被规避的非pythonic黑客攻击。

Python的对象继承模型被设计为开放的,任何尝试以另一种方式尝试都会使问题过于复杂,而这个问题实际上并不存在。告诉每个人使用你的东西要么遵循你的“规则”,要么程序会搞砸。

答案 3 :(得分:2)

一个没有太大魔力的明确解决方案是维护一个准备回调列表:

class BaseHandler(object):
    def __init__(self):
        self.prepare_callbacks = []
    def register_prepare_callback(self, callback):
        self.prepare_callbacks.append(callback)
    def prepare(self):
        # Do BaseHandler preparation
        for callback in self.prepare_callbacks:
            callback()

class MyHandler(BaseHandler):
    def __init__(self):
        BaseHandler.__init__(self)
        self.register_prepare_callback(self._prepare)
    def _prepare(self):
        # whatever

答案 4 :(得分:0)

一般情况下,您可以尝试使用__getattribute__来实现这样的事情(直到有人覆盖此方法的那一刻),但它违背了Python的想法。有理由能够在Python中访问私有对象成员。原因在import this

中提到