Python:抽象类__init__

dab*_*aba 28 python oop abstract-class python-2.7

我试图A用一个默认行为的构造函数声明一个抽象类:所有子类必须初始化一个成员self.n:

from abc import ABCMeta

class A(object):
    __metaclass__ = ABCMeta

    def __init__(self, n):
        self.n = n
Run Code Online (Sandbox Code Playgroud)

但是,我不想让A类被实例化,因为它是一个抽象类.问题是,这实际上是允许的:

a = A(3)
Run Code Online (Sandbox Code Playgroud)

当我期望它应该时,这不会产生任何错误.

那么:如何在为构造函数定义默认行为时定义不可实例化的抽象类?

Mik*_*ler 33

制作__init__一个抽象的方法:

from abc import ABCMeta, abstractmethod

class A(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self, n):
        self.n = n


if __name__ == '__main__':
    a = A(3)
Run Code Online (Sandbox Code Playgroud)

帮助:

TypeError: Can't instantiate abstract class A with abstract methods __init__
Run Code Online (Sandbox Code Playgroud)

Python 3版本:

from abc import ABCMeta, abstractmethod

class A(object, metaclass=ABCMeta):

    @abstractmethod
    def __init__(self, n):
        self.n = n


if __name__ == '__main__':
    a = A(3)
Run Code Online (Sandbox Code Playgroud)

也适用:

TypeError: Can't instantiate abstract class A with abstract methods __init__
Run Code Online (Sandbox Code Playgroud)

  • 这仍然需要在每个基类中定义`__init__`(使用super`()`调用). (8认同)
  • 引用我自己的类似答案:问题:如果您需要将构造函数显式指定为抽象方法,那么将类定义为抽象的意义何在?(注意我并不是暗示所有抽象类都是,只是一个不可实例化的类)我希望这种行为作为抽象类的默认行为 (2认同)
  • @dabadaba:将元类设置为ABCmeta不会将类声明为抽象,而只能做到这一点(通过将方法之一声明为抽象)。 (2认同)

gip*_*psy 6

一个不太优雅的解决方案可能是这样的:

class A(object):
  def __init__(self, n):
    if self.__class__ == A:
      raise Exception('I am abstract!')
    self.n = n
Run Code Online (Sandbox Code Playgroud)

用法

class B(A):
  pass
a = A(1)  # Will throw exception
b = B(1)  # Works fine as expected.
Run Code Online (Sandbox Code Playgroud)


Ash*_*ary 6

您可以重写__new__方法以防止直接实例化。

class A(object):
    __metaclass__ = ABCMeta

    def __new__(cls, *args, **kwargs):
        if cls is A:
            raise TypeError(
                "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
            )
        return object.__new__(cls)
Run Code Online (Sandbox Code Playgroud)

输出:

>>> A()
Traceback (most recent call last):
  File "<ipython-input-8-3cd318a12eea>", line 1, in <module>
    A()
  File "/Users/ashwini/py/so.py", line 11, in __new__
    "TypeError: Can't instantiate abstract class {name} directly".format(name=cls.__name__)
TypeError: TypeError: Can't instantiate abstract class A directly
Run Code Online (Sandbox Code Playgroud)