回答:
時々表示されるのは次のとおりです。
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スタイルの区別は存在しません。誰かが正式なインターフェースを定義しようと努力すれば、それも抽象クラスになります。唯一の違いは、ドキュメント文字列に記載されている意図にあります。
そして、抽象型とインターフェースの違いは、あなたがアヒルのタイピングをしているときのヘアスプリットです。
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
これは、ミックスインを含む一種の抽象スーパークラスを使用して、素である具象サブクラスを作成します。
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
より有益なエラーメッセージです:)
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__
だから我々は、で実装するのに必要とされる以上 __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
たとえば、「有効」は、言葉で表現できるものとして定義されます。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のカスタムオブジェクトのインターフェースを定義することを示しました。
Python> = 2.6には、抽象基本クラスがあります。
抽象基本クラス(略称ABC)は、hasattr()などの他の手法が不格好な場合にインターフェースを定義する方法を提供することにより、ダックタイピングを補完します。Pythonには、データ構造(collectionsモジュール内)、数値(numbersモジュール内)、およびストリーム(ioモジュール内)用の多くの組み込みABCが付属しています。abcモジュールで独自のABCを作成できます。
Zopeインターフェースモジュールもあり、これはツイストのようにzopeの外部のプロジェクトで使用されます。私はそれで本当に慣れていないんだけど、wikiページがありますここにいるかもしれないのヘルプが。
一般に、抽象クラスの概念やPythonのインターフェースは必要ありません(編集-詳細はS.Lottの回答を参照)。
Pythonにはどちらの概念もありません。
それはインターフェイスの必要性を取り除いたダックタイピングを使用します(少なくともコンピューターでは:-))
Python <= 2.5:基本クラスは明らかに存在しますが、メソッドを「純粋仮想」としてマークする明示的な方法がないため、クラスは実際には抽象的ではありません。
Python> = 2.6:抽象基本クラスが存在します(http://docs.python.org/library/abc.html)。また、サブクラスで実装する必要があるメソッドを指定できます。構文はあまり好きではありませんが、機能はあります。ほとんどの場合、「使用する」クライアント側からダックタイピングを使用する方が良いでしょう。
説明するためのより基本的な方法:インターフェースは、空のマフィン鍋のようなものです。これは、コードを持たない一連のメソッド定義を含むクラスファイルです。
抽象クラスも同じですが、すべての関数を空にする必要はありません。いくつかはコードを持つことができます。完全に空ではありません。
区別する理由:Pythonには実用的な違いはあまりありませんが、大規模なプロジェクトの計画レベルでは、コードがないため、インターフェースについて話す方が一般的かもしれません。特に、この用語に慣れているJavaプログラマーと作業している場合はなおさらです。
一般に、インターフェイスは、単一継承クラスモデルを使用する言語でのみ使用されます。これらの単一継承言語では、いずれかのクラスが特定のメソッドまたはメソッドのセットを使用できる場合、通常はインターフェイスが使用されます。また、これらの単一継承言語では、抽象クラスを使用して、メソッドなしまたは複数のメソッドに加えてクラス変数を定義するか、単一継承モデルを利用して、一連のメソッドを使用できるクラスの範囲を制限します。
多重継承モデルをサポートする言語は、インターフェイスではなく、クラスまたは抽象基本クラスのみを使用する傾向があります。Pythonは多重継承をサポートしているため、インターフェイスを使用せず、基本クラスまたは抽象基本クラスを使用する必要があります。
抽象クラスは、1つ以上の抽象メソッドを含むクラスです。抽象メソッドに加えて、抽象クラスは静的メソッド、クラスメソッド、およびインスタンスメソッドを持つことができます。しかし、インターフェースの場合、それは他ではなく抽象的なメソッドのみを持ちます。したがって、抽象クラスの継承は必須ではありませんが、インターフェースの継承は必須です。
完全を期すために 、ABCが導入され、インターフェイスと比較されたPEP3119、およびオリジナルのTalinのコメントに言及する必要があります。
抽象クラスは完全なインターフェースではありません:
しかし、あなたがそれをあなた自身の方法で書くことを検討するならば:
def some_function(self):
raise NotImplementedError()
interface = type(
'your_interface', (object,),
{'extra_func': some_function,
'__slots__': ['extra_func', ...]
...
'__instancecheck__': your_instance_checker,
'__subclasscheck__': your_subclass_checker
...
}
)
ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...
最終的に達成するためのホイールを発明していることをかなり速く気づくでしょう
abc.ABCMeta
abc.ABCMeta
不足しているインターフェース機能の便利な追加として提案されましたが、それはpythonのような言語で十分です。
確かに、バージョン3を記述し、新しい構文と不変のインターフェイスコンセプトを追加する間に、より良く拡張することができました...
結論:
The abc.ABCMeta IS "pythonic" interface in python