“ABC”类是做什么的?

6

我编写了一个继承另一个类的类:

class ValueSum(SubQuery):
    output = IntegerField()

Pycharm显示以下警告:

Class ValueSum必须实现所有抽象方法

然后我使用alt+enterABC添加到超类,那么我的警告就消失了。我有几个问题:

  • 在编写子类时,我应该总是这样做吗?

  • 手动实现所有方法与仅使用ABC之间的区别是什么?

  • ABC是否为我的代码添加了某些内容?


什么是SubQuery - Chayim Friedman
"SubQuery" 是 Django 模型表达式。 - nonsensei
3个回答

7

SubQuery是一个抽象基类(根据abc模块),其中有一个或多个您未覆盖的抽象方法。通过将ABC添加到基类列表中,您定义了ValueSum本身为抽象基类。这意味着您不必强制重写这些方法,但也意味着您不能实例化ValueSum本身。

PyCharm提前警告您需要实现从SubQuery继承的抽象方法;如果您不这样做,当您尝试实例化ValueSum时,Python会报错。


关于继承自ABC的作用,答案是...并没有太多作用。这只是为了方便设置元类。以下两种方式是等效的:
class Foo(metaclass=abc.ABCMeta):
    ...

并且

class Foo(abc.ABC):
    ...

元类修改了__new__方法,以便于每次尝试创建您的类的实例时都会检查该类是否已经实现了父类中用@abstractmethod装饰的所有方法。

2
“抽象基类”或abc.ABC是一个辅助类。

https://docs.python.org/3/library/abc.html

这里是它们存在的一部分原因:
collections模块有一些具体的类,它们派生自ABCs;当然,它们还可以进一步派生。此外,collections.abc子模块有一些ABCs,可用于测试类或实例是否提供特定接口,例如它是否可哈希或是否为映射。
这里有一个很好的例子:https://pymotw.com/2/abc/ | https://pymotw.com/3/abc/ 来自pymotw的内容:
如果忘记正确设置元类,则具体实现将不会强制执行其API。为了更容易地设置抽象类,请提供一个基类,该基类会自动设置元类。
abc_abc_base.py
import abc


class PluginBase(abc.ABC):

    @abc.abstractmethod
    def load(self, input):
        """Retrieve data from the input source
        and return an object.
        """

    @abc.abstractmethod
    def save(self, output, data):
        """Save the data object to the output."""


class SubclassImplementation(PluginBase):

    def load(self, input):
        return input.read()

    def save(self, output, data):
        return output.write(data)


if __name__ == '__main__':
    print('Subclass:', issubclass(SubclassImplementation,
                                  PluginBase))
    print('Instance:', isinstance(SubclassImplementation(),
                                  PluginBase))

2
这是面向对象编程(OOP)中抽象类的主要要点。继承自抽象类的类需要实现所有抽象方法。如果它们本身是抽象的,则不需要。那些抽象方法就像接口的方法签名,里面没有任何实现。因此,您不能创建一个未实现所有抽象方法的非抽象类。 ABC只是一个辅助类,通过从它派生新的抽象类。在这里,您可以阅读有关Python中抽象类的更多信息:https://docs.python.org/3/library/abc.html 根据您的观察,您将ValueSum标记为抽象。这意味着,ValueSum的所有子类都需要实现ValueSum和所有抽象超类的抽象方法,包括SubQuery

我写了一个抽象类。

不是。您编写了一个继承另一个类的类。

我写子类时应该总是这样做吗?

不是。只有当您想让类成为抽象类时才需要这样做。

手动实现所有方法与仅使用ABC之间有什么区别?

在这种情况下,您正在将实现转发给ValueSum的所有子类。不使用ABC将强制您在ValueSum内部实现抽象方法。

ABC对我的代码有什么影响吗?

没有。无论如何,都不会比使用其他类/继承更多。

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