web-dev-qa-db-ja.com

Pythonの抽象クラスとインタフェースの違い

Pythonの抽象クラスとインタフェースの違いは何ですか?

499
gizmo

あなたが時々見るものは以下の通りです:

class Abstract1( object ):
    """Some description that tells you it's abstract,
    often listing the methods you're expected to supply."""
    def aMethod( self ):
        raise NotImplementedError( "Should have implemented this" )

Pythonは正式なインタフェース規約を持っていない(そして必要としていない)ので、抽象化とインタフェースの間のJavaスタイルの区別は存在しません。誰かが正式なインタフェースを定義しようとする努力をすれば、それは抽象クラスにもなります。唯一の違いはdocstringで述べられている意図にあるでしょう。

抽象とインタフェースの違いは、アヒルの打鍵があるときには髪を分割することです。

Javaは多重継承を持たないのでインターフェースを使います。

Pythonには多重継承があるので、このようなものも見られるかもしれません

class SomeAbstraction( object ):
    pass # lots of stuff - but missing something

class Mixin1( object ):
    def something( self ):
        pass # one implementation

class Mixin2( object ):
    def something( self ):
        pass # another

class Concrete1( SomeAbstraction, Mixin1 ):
    pass

class Concrete2( SomeAbstraction, Mixin2 ):
    pass

これはミックスインを含む一種の抽象スーパークラスを使用して、互いに素な具象サブクラスを作成します。

570
S.Lott

Pythonの抽象クラスとインタフェースの違いは何ですか?

オブジェクトのインターフェースは、そのオブジェクトの一連のメソッドと属性です。

Pythonでは、抽象基底クラスを使ってインターフェースを定義し、強制することができます。

抽象基本クラスの使い方

たとえば、collectionsモジュールの抽象基底クラスの1つを使用したいとします。

import collections
class MySet(collections.Set):
    pass

それを使用しようとすると、作成したクラスは期待される集合の振る舞いをサポートしていないので、TypeErrorが得られます。

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

したがって、 least __contains____iter__、および__len__を実装する必要があります。 ドキュメント からこの実装例を使ってみましょう。

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

実装:抽象基底クラスの作成

メタクラスをabc.ABCMetaに設定し、関連メソッドにabc.abstractmethodデコレータを使用することで、独自の抽象基本クラスを作成できます。メタクラスは装飾された関数を__abstractmethods__属性に追加し、それらが定義されるまでインスタンス化を防ぎます。

import abc

たとえば、 "effable"は言葉で表現できるものとして定義されます。 Python 2で、有効な抽象基底クラスを定義したいとします。

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

あるいはPython 3では、メタクラス宣言がわずかに変更されています。

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

インターフェースを実装せずに効率的なオブジェクトを作成しようとした場合:

class MyEffable(Effable): 
    pass

インスタンス化してみます。

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

仕事が終わっていないと言われます。

期待されるインターフェースを提供することでこれを遵守するならば:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

抽象クラスから派生したクラスの具象バージョンを使用することができます。

>>> me = MyEffable()
>>> print(me)
expressable!

これらのインタフェースを既に実装している仮想サブクラスを登録するなど、これを使ってできることは他にもありますが、それはこの質問の範囲外です。ここで示されている他の方法は、そうするためにabcモジュールを使ってこの方法を適応させる必要があります。

結論

抽象基底クラスの作成がPythonのカスタムオブジェクトのためのインターフェースを定義することを実証しました。

159
Aaron Hall

Python> = 2.6は 抽象基底クラス を持っています。

Abstract Base Classes(略してABC)は、hasattr()のような他の方法では不器用な場合にインタフェースを定義する方法を提供することによってアヒルタイピングを補完します。 Pythonには、データ構造(collectionsモジュール内)、数値(numbersモジュール内)、およびストリーム(ioモジュール内)のための多くの組み込みABCが付属しています。あなたはabcモジュールであなた自身のABCを作成することができます。

Zopeインターフェース モジュールもあります。これは、ツイストのように、zope以外のプロジェクトで使用されます。あまり慣れていませんが、役に立つウィキページ here があります。

一般的に、抽象クラスやpythonのインターフェースの概念は必要ありません(編集 - 詳細についてはS.Lottの回答を参照してください)。

99
JimB

Pythonはどちらの概念も実際には持っていません。

ダックタイピングを使用しているため、インタフェースが不要になりました(少なくともコンピュータでは:-))。

Python <= 2.5:基本クラスは明らかに存在しますが、メソッドを '純粋仮想'としてマークする明示的な方法はないので、クラスは本当に抽象的ではありません。

Python> = 2.6:抽象基底クラスは existhttp://docs.python.org/library/abc.html )します。また、サブクラスに実装する必要があるメソッドを指定することもできます。構文はあまり好きではありませんが、機能はあります。ほとんどの場合、 'using'クライアント側からダックタイピングを使用するほうがおそらく良いでしょう。

37
Douglas Leeder

より基本的な方法で説明すると、インターフェースは一種の空のマフィンパンのようなものです。コードを持たない一連のメソッド定義を含むクラスファイルです。

抽象クラスも同じですが、すべての関数が空である必要はありません。一部の人はコードを持つことができます。厳密には空ではありません。

区別する理由:Pythonにはそれほど実用的な違いはありませんが、大規模プロジェクトの計画レベルでは、コードがないため、インターフェースについて話すほうが一般的です。特に、その用語に慣れているJavaプログラマーと仕事をしているのであれば。

29
SilentSteel

一般に、インターフェースは単一継承クラスモデルを使用する言語でのみ使用されます。これらの単一継承言語では、インタフェースは通常、クラスが特定のメソッドまたは一連のメソッドを使用できる場合に使用されます。これらの単一継承言語でも、抽象クラスは、1つ以上のメソッドに加えてクラス変数を定義するため、または単一継承モデルを利用して一連のメソッドを使用できるクラスの範囲を制限するために使用されます。

多重継承モデルをサポートする言語は、クラスまたは抽象基本クラスのみを使用し、インターフェースは使用しない傾向があります。 Pythonは多重継承をサポートしているので、インターフェースを使用せず、基本クラスまたは抽象基本クラスを使用したいと思うでしょう。

http://docs.python.org/library/abc.html

15
Lara Dougan

抽象クラスは、1つ以上の抽象メソッドを含むクラスです。抽象メソッドに加えて、抽象クラスには静的メソッド、クラスメソッド、およびインスタンスメソッドを含めることができます。ただし、インターフェイスの場合、抽象メソッドは他にないだけです。したがって、抽象クラスを継承することは必須ではありませんが、インターフェイスを継承することは必須です。

0
Akash Ukarande