8

抽象基类在 Python 中仍然很方便。在编写一个我希望每个子类都有一个spam()方法的抽象基类时,我想写这样的东西:

class Abstract(object):
    def spam(self):
        raise NotImplementedError

挑战来自还想要使用super(),并通过将其包含在整个子类链中来正确地做到这一点。在这种情况下,似乎我必须super像下面这样包装每个调用:

class Useful(Abstract):
    def spam(self):
        try:
            super(Useful, self).spam()
        except NotImplementedError, e:
            pass
        print("It's okay.")

这对于一个简单的子类来说是可以的,但是当编写一个有很多方法的类时,try-except 会变得有点麻烦,而且有点难看。有没有更优雅的从抽象基类子类化的方式?我只是做错了吗?

4

3 回答 3

11

您可以使用abc 模块在 python 2.6+ 中干净地执行此操作:

import abc
class B(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def foo(self):
        print 'In B'

class C(B):
    def foo(self):
        super(C, self).foo()
        print 'In C'

C().foo()

输出将是

In B
In C
于 2011-01-25T22:12:48.573 回答
7

不要写所有的代码。对抽象类的简单检查可以节省您编写所有代码的时间。

如果方法是抽象的,具体的子类不会调用 super。

如果方法是具体的,具体的子类会调用 super。

于 2011-01-25T22:27:28.617 回答
4

理解这一点的关键super()是实现协作继承。类如何合作取决于程序员。super()不是魔术,也不知道你想要什么!将 super 用于不需要协作继承的平面层次结构没有多大意义,因此在这种情况下,S. Lott 的建议是正确的。Useful 的子类可能会也可能不想使用,super()这取决于他们的目标:)

例如:Abstract 是 A.A <- B,但是你想支持 C 的插入,比如 A <- C <- B。

class A(object):                                                                                         
    """I am an abstract abstraction :)"""
    def foo(self):
        raise NotImplementedError('I need to be implemented!')

class B(A):
    """I want to implement A"""
    def foo(self):
        print('B: foo')
        # MRO Stops here, unless super is not A
        position = self.__class__.__mro__.index
        if not position(B) + 1 == position(A):
            super().foo()

b = B()     
b.foo()

class C(A):
    """I want to modify B and all its siblings (see below)"""
    def foo(self):
        print('C: foo')
        # MRO Stops here, unless super is not A
        position = self.__class__.__mro__.index
        if not position(C) + 1 == position(A):
            super().foo()

print('')   
print('B: Old __base__ and __mro__:\n')
print('Base:', B.__bases__)
print('MRO:', B.__mro__)
print('')
# __mro__ change implementation
B.__bases__ = (C,)
print('B: New __base__ and __mro__:\n')
print('Base:', B.__bases__)
print('MRO:', B.__mro__)
print('')
b.foo()

和输出:

B: foo

B: Old __base__ and __mro__:

Base: (<class '__main__.A'>,)
MRO: (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

B: New __base__ and __mro__:

Base: (<class '__main__.C'>,)
MRO: (<class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

B: foo
C: foo
于 2012-11-27T20:52:26.937 回答