【问题标题】:Python different behaviour with abstractmethodPython与abstractmethod的不同行为
【发布时间】:2014-09-19 08:30:33
【问题描述】:

我有两个类继承自同一个父级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继承自tupleP,而C仅继承自P

现在这是行为:c = C() 出现错误,正如预期的那样:

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

但是d = D() 可以正常工作!

我什至可以拨打d.foo()。我该如何解释这种行为?

【问题讨论】:

  • 仅供参考,使用 Python 3 它们都可以很好地实例化。
  • 大写字母类对你有用吗?您没有收到任何语法错误吗?
  • @Keith 是首选吗?为什么abstractmethod 不起作用?
  • @Keith:那是因为在 Python 3 中你需要调整元类语法; class P(metaclass=ABCMeta):。一旦你这样做了,你会在 Python 3 上看到同样的问题,C() 会抛出异常,D() 不会。
  • @tilaprimera 谢谢,我的错别字

标签: python abstract-class abc


【解决方案1】:

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

【讨论】:

  • 伙计,你是个传奇 :)
猜你喜欢
  • 2011-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 2016-09-20
相关资源
最近更新 更多