20

我来自 C# 背景,该语言具有一些内置的“保护开发人员”功能。我了解 Python 采用“我们都是成年人”的方法,并让开发人员负责认真仔细地编写代码。

也就是说,Python 建议私有实例变量使用前导下划线等约定。我的问题是,除了在文档字符串中指定它之外,是否有将类标记为抽象的特定约定? 我在 python 样式指南中没有看到任何特别提到抽象类命名约定的内容。

到目前为止,我可以想到 3 个选项,但我不确定它们是否是好主意:

  1. 在类上方的文档字符串中指定它(可能会被忽略)
  2. 在类名中使用前导下划线(不确定这是否被普遍理解)
  3. 在引发错误def __init__(self):的抽象类上创建一个方法(不确定这是否会对继承产生负面影响,例如如果您想调用基本构造函数)

其中一个是不错的选择还是有更好的选择?我只是想确保其他开发人员知道它是抽象的,因此如果他们尝试实例化它,他们应该为任何奇怪的行为承担责任。

4

6 回答 6

24

如果您使用的是 Python 2.6 或更高版本,则可以使用标准库中的抽象基类模块来强制执行抽象性。这是一个例子:

from abc import ABCMeta, abstractmethod

class SomeAbstractClass(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def this_method_must_be_overridden(self):
        return "But it can have an implementation (callable via super)."

class ConcreteSubclass(SomeAbstractClass):
    def this_method_must_be_overridden(self):
        s = super(ConcreteSubclass, self).this_method_must_be_overridden()
        return s.replace("can", "does").replace(" (callable via super)", "")

输出:

>>> a = SomeAbstractClass()
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    a = SomeAbstractClass()
TypeError: Can't instantiate abstract class SomeAbstractClass with abstract
methods this_method_must_be_overridden
>>> c = ConcreteSubclass()
>>> c.this_method_must_be_overridden()
'But it does have an implementation.'
于 2013-02-20T06:49:15.803 回答
5

根据你的最后一句话,我会回答“只是记录它”。任何以文档规定的方式使用类的人都必须为任何奇怪的行为承担责任。

Python 中有一个抽象基类机制,但如果您的唯一目标是阻止实例化,我认为没有任何理由使用它。

于 2013-02-20T05:14:09.263 回答
3

创建您的“抽象”类和raise NotImplementedError()抽象方法。

它不会阻止人们使用该类,并且以真正的鸭式打字方式,它会让您知道您是否忽略了实现抽象方法。

于 2013-02-20T06:03:52.967 回答
3

我只是用前缀“抽象”来命名我的抽象类。例如 AbstractDevice、AbstractPacket 等。

它就像它来的一样简单和重要。如果其他人选择继续实例化和/或使用以“抽象”一词开头的类,那么他们要么知道自己在做什么,要么无论如何都没有希望。

如此命名它也提醒我自己不要对深度抽象层次结构发疯,因为将“抽象”放在很多类的前面也感觉很愚蠢。

于 2013-02-20T06:25:18.987 回答
0

强制执行是可能的,但相当不合情理。当我在多年的 C++ 编程之后来到 Python 时,我也尝试过这样做,我想,如果他们有更经典的语言经验,大多数人都会尝试这样做。元类可以完成这项工作,但无论如何 Python 在编译时检查的东西很少。您的检查仍将在运行时执行。那么,如果仅在运行时发现无法创建某个类真的那么有用吗?在 C++(以及 C#)中,您甚至无法编译创建抽象类的代码,这就是重点——尽早发现问题。如果你有抽象方法,提出一个NotImplementedError例外似乎已经足够了。注意:提高,不返回错误代码!在 Python 中,错误通常不应该是沉默的,除非它们被明确地沉默。记录。以一种抽象的方式命名一个类。就这样。

Python 代码的质量主要通过与具有高级编译时类型检查的语言中使用的方法完全不同的方法来确保。就我个人而言,我认为动态类型的 lngauges 和其他之间最严重的区别。单元测试、覆盖分析等。因此,代码的设计完全不同:所做的一切都不是为了强制执行,而是为了让测试尽可能容易。

于 2013-02-20T07:01:52.390 回答
0

在 Python 3.x 中,您的类可以继承自abc.ABC. 这将使您的类不可实例化,如果您尝试这样做,您的 IDE 会警告您。

import abc

class SomeAbstractClass(abc.ABC):
    @abc.abstractmethod
    def some_abstract_method(self):
        raise NotImplementedError()
    
    @property
    @abc.abstractmethod
    def some_abstract_property(self):
        raise NotImplementedError()

这首先在PEP 3119中提出。

于 2022-02-13T12:44:16.563 回答