如何确保我的类方法在子类重写时仍被调用?

13 投票
5 回答
1929 浏览
提问于 2025-04-17 05:26

举个例子,我有一个

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

我不想让每个从BaseHandler继承的类,以及那些想要实现prepare方法的类,都必须记得去调用

super(SubBaseHandler, self).prepare()

有没有办法确保即使子类也实现了prepare方法,父类的方法仍然会被执行呢?

5 个回答

3

你只需要接受一个事实:当别人想要修改你写的类的时候,必须告诉他们要调用基类的方法。其他的解决办法要么需要你再给他们解释别的事情,要么就是一些不太符合Python风格的技巧,这些技巧也可能会被绕过。

Python的对象继承模型是设计得很开放的,试图去改变这个模型只会让问题变得复杂,而这个问题其实根本就不存在。你只需要告诉使用你代码的人,要么遵循你的“规则”,要么程序就会出问题。

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,因为这正是它的用途。

16

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

使用元类可以确保实现BaseHandler的人,所有的子类都会调用父类的prepare()方法,而不需要对现有的代码做任何修改。

这个元类会检查两个类中是否有prepare方法的实现,然后把子类的prepare方法替换成一个新的方法,这个新方法会先调用父类的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

撰写回答