尽管使用abc(抽象基类),仍能实例化Python类。

10
这是关于这个问题的答案,旨在使用Python的abc模块创建抽象类(由@alexvassel回答并被接受)。我尝试了这些建议,但奇怪的是,即使我按照使用abc的建议操作,它也无法为我工作。因此,我在这里发布了一个问题:
以下是我的Python代码:
from abc import ABCMeta, abstractmethod

class Abstract(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def foo(self):
        print("tst")

a = Abstract()
a.foo()

当我执行这个模块时,这是在我的控制台上的输出:

pydev debugger: starting (pid: 20388)
tst

与那个被接受的答案相反

>>> TypeError: Can not instantiate abstract class Abstract with abstract methods foo

那我到底做对了什么,做错了什么?为什么有些事情能成功而有些事情会失败?非常感谢专家们的深入解析。

2个回答

8
在Python 3中创建抽象基类时,请使用metaclass参数:
from abc import ABCMeta, abstractmethod

class Abstract(metaclass=ABCMeta):

    @abstractmethod
    def foo(self):
        print("tst")

a = Abstract()
a.foo()

1
我明白了。这是很好的信息。按照建议修改定义后,它可以工作。谢谢。 - jark
2
如果抽象类没有任何@abstractmethod,则似乎可以实例化并调用其方法。 - Peter

6
在Python 2中,你必须这样分配元类:
import abc

class ABC(object):

    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def foo(self):
        return True

a = ABC()

这引发了一个“TypeError”错误。
Traceback (most recent call last):
  File "<pyshell#59>", line 1, in <module>
    a = ABC()
TypeError: Can't instantiate abstract class ABC with abstract methods foo

但在Python 3中,将__metaclass__赋值为属性无效(与您的意图相反,但解释器不认为它是一个错误,只是像任何其他属性一样的普通属性,这就是为什么上面的代码不会引发错误)。现在,元类被定义为类的命名参数:

import abc

class ABC(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def foo(self):
        return True

a = ABC()

引发 TypeError 错误:

Traceback (most recent call last):
  File "main.py", line 11, in 
    a = ABC()
TypeError: Can't instantiate abstract class ABC with abstract methods foo

感谢您对为什么Python 2不会出错进行详细的解释。我希望它会出错,而不是静默地工作,因为这不是我想要的 :( - jark
@jark 很有趣,因为 Victory 的代码在 Python 3 上是无效的,实际上也没有展示出你所寻找的内容。 - Russia Must Remove Putin
Aaron Hall,感谢您的反馈。我接受了Victory的答案,因为那是第一个我看到并尝试后能按照我的期望工作的答案。我不确定您为什么说它“无效于Python 3”?如果我将您在解决方案中发布的代码与Victory发布的代码进行比较,两者都使用完全相同的逻辑。唯一的区别是您使用了“import abc”(然后使用abc.abstract方法等),而Victory使用“from abc import ABCMeta,abstractmethod”并使用abstractmethod等。这与您无关,也与Victory无关。 - jark
我很感谢您详细的回答。但请再次让我知道我是如何误解 Victory 的答案以及为什么它行不通,我会考虑接受您的建议。 - jark
@jark,他的代码在a = Abstract()处出现错误(这是应该的),并且a.foo()是无关紧要的。显然,他没有测试过自己的代码,只是简单地复制了你的代码并进行了修改。尽管如此,请接受你认为最有帮助的答案。 - Russia Must Remove Putin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接