Python与abstractmethod的不同行为

时间:2014-07-28 07:29:38

标签: python abstract-class abc

我有两个继承自同一个父P的类:

from abc import ABCMeta, abstractmethod

class P(object):

    __metaclass__ = ABCMeta

    @abstractmethod  
    def foo(self):
        pass

class C(P):
    pass

class D(tuple, P):
    pass

唯一的区别是D继承自tuplePC仅从P继承。

现在这是行为:c = C()错误,正如所料:

TypeError: Can't instantiate abstract class C with abstract methods foo

d = D()无误地运行!

我甚至可以致电d.foo()。我该如何解释这种行为?

1 个答案:

答案 0 :(得分:8)

object.__new__方法中测试抽象方法;当您从具有自己的tuple方法的__new__继承时,不会调用object.__new__并且不会对抽象方法进行测试。

换句话说,将抽象方法与任何的内置不可变类型混合将导致此问题。

唯一有效的解决方案是在__new__中进行自己的测试,然后只有在 tuple之前放置抽象类时在子类中的两个碱基中混合。

class P(object):
    __metaclass__ = ABCMeta

    def __new__(cls, *args, **kwargs):
        super_new = super(P, cls).__new__
        if super_new.__self__ is not object:
            # immutable mix-in used, test for abstract methods
            if getattr(cls, '__abstractmethods__'):
                raise TypeError(
                    "Can't instantiate abstract class %s "
                    "with abstract methods %s" % (
                        cls.__name__,
                        ', '.join(sorted(cls.__abstractmethods__))))

        return super_new(cls, *args, **kwargs)

    @abstractmethod  
    def foo(self):
        pass

class D(P, tuple):
    pass