web-dev-qa-db-ja.com

Python:抽象クラス__init__

抽象クラスAをデフォルトの動作を持つコンストラクターで宣言しようとしています。すべてのサブクラスはメンバーself.nを初期化する必要があります。

from abc import ABCMeta

class A(object):
    __metaclass__ = ABCMeta

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

ただし、Aクラスはインスタンス化されません。これは、抽象クラスであるためです。問題は、これが実際に許可されていることです:

a = A(3)

期待どおりにエラーが発生することはありません。

だから:コンストラクタのデフォルトの動作を定義しながら、インスタンス化できない抽象クラスをどのように定義できますか?

20
dabadaba

__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)

役立ちます:

TypeError: Can't instantiate abstract class A with abstract methods __init__

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)

同様に動作します:

TypeError: Can't instantiate abstract class A with abstract methods __init__
25
Mike Müller

@abc.abstractmethodデコレータを使用して、メソッドを抽象として定義する必要があります。

__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)

出力:

>>> 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
3

それほどエレガントではない解決策はこれです:

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

使用法

class B(A):
  pass
a = A(1)  # Will throw exception
b = B(1)  # Works fine as expected.
2
gipsy