Pythonでインターフェイスを実装するにはどうすればよいですか?


182
public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

    public void show()
    {
        Console.WriteLine("Hello World!");
    }

    #endregion
}

このC#コードに相当するPythonを実装するにはどうすればよいですか?

class IInterface(object):
    def __init__(self):
        pass

    def show(self):
        raise Exception("NotImplementedException")


class MyClass(IInterface):
   def __init__(self):
       IInterface.__init__(self)

   def show(self):
       print 'Hello World!'

これは良いアイデアですか?回答に例を挙げてください。


あなたのケースでインターフェイスを使用する目的は何ですか?
Bandi-T

23
率直に言って、まったく目的がありません!私はあなたがPythonでインターフェースが必要なときに何をすべきかを学びたいですか?
Pratik Deoghare、2010年

18
raise NotImplementedErrorshow体がどうあるべきかException-Pythonが完全に特定の組み込みのものを定義するときに完全にジェネリックを上げることは意味がありません!-)
Alex Martelli

2
IInterfaceでshow()を初期化して呼び出さない(または例外自体を発生させる)べきではないので、抽象インターフェースをインスタンス化できませんか?
Katastic Voyage 2017

1
私はこれのいくつかの用途を見ることができます...特定の署名を確実にしたいオブジェクトがあるとしましょう。ダックタイピングでは、オブジェクトが期待どおりの署名であることを保証できません。動的に型付けされたプロパティに何らかの型付けを強制すると便利な場合があります。
Prime By Design

回答:


151

ここで他の人が述べたように:

Pythonではインターフェイスは必要ありません。これは、Pythonに適切な多重継承とダックタイピングがあるためです。つまり、Javaでインターフェースを用意する必要がある場所で、Pythonにインターフェースを用意する必要ありません。

とは言っても、インターフェースにはまだいくつかの用途があります。それらのいくつかは、Python 2.6で導入されたPython抽象基本クラスでカバーされています。インスタンス化できない基本クラスを作成したいが、特定のインターフェースまたは実装の一部を提供する場合に、これらは役立ちます。

別の使用法は、オブジェクトが特定のインターフェースを実装することをどういうわけか指定したい場合で、それらからサブクラス化することによってそのためにもABCを使用できます。もう1つの方法は、Zopeコンポーネントインターフェースの一部であるモジュールであるzope.interfaceです。これは、非常に優れたコンポーネントフレームワークです。ここでは、インターフェイスからサブクラス化するのではなく、クラス(またはインスタンス)をインターフェイスの実装としてマークします。これは、コンポーネントレジストリからコンポーネントを検索するためにも使用できます。超クール!


11
これについて詳しく説明してもらえますか?1.そのようなインターフェースをどのように実装しますか?2.コンポーネントの検索にどのように使用できますか?
ジオイデシック2018年

42
「インターフェースはPythonでは必要ありません。必要な場合を除きます。」
バプティストカンデリエ

8
インターフェースは主に、予測可能な結果を​​得るために使用されます/オブジェクトを渡すときにメンバーの正確さを強制します。pythonがこれをオプションとしてサポートしているとしたらすばらしいでしょう。また、開発ツールのインテリセンスを向上させることもできます
Sonic Soul

1
例をあげると、この答えが大幅に改善されます。
ボブ

5
「これはPythonが適切な多重継承を持っているためです」と、誰がインターフェースが多重継承のためのものであると述べましたか
adnanmuttaleb

76

抽象基本クラスにabcモジュールを使用すると、うまくいくようです。

from abc import ABCMeta, abstractmethod

class IInterface:
    __metaclass__ = ABCMeta

    @classmethod
    def version(self): return "1.0"
    @abstractmethod
    def show(self): raise NotImplementedError

class MyServer(IInterface):
    def show(self):
        print 'Hello, World 2!'

class MyBadServer(object):
    def show(self):
        print 'Damn you, world!'


class MyClient(object):

    def __init__(self, server):
        if not isinstance(server, IInterface): raise Exception('Bad interface')
        if not IInterface.version() == '1.0': raise Exception('Bad revision')

        self._server = server


    def client_show(self):
        self._server.show()


# This call will fail with an exception
try:
    x = MyClient(MyBadServer)
except Exception as exc:
    print 'Failed as it should!'

# This will pass with glory
MyClient(MyServer()).client_show()

11
言語そのものの一部、またはIMOでまったく使用しないモジュールを必要としています。
Mike de Klerk

どういう意味if not server.version() == '1.0': raise ...ですか?私は本当にこの行を取得しません。説明は大歓迎です。
Skandix

1
@MikedeKlerk私はこれ以上同意できませんでした。Pythonがタイピングに答えるように; 型を型にしたいことを宣言するためにモジュールをインポートする必要はありません。これに対する応答は、通常「Pythonは動的に型付けされます」ですが、それは言い訳にはなりません。Java + Groovyはこの問題を解決します。静的なものにはJava、動的なものにはGroovy。
ubiquibacon

6
@ MikedeKlerk、abcモジュールは実際にPythonに組み込まれています。これらのパターンのいくつかを設定するのは少し手間がかかります。なぜなら、「よりPython的」と見なされる代替パターンのために、Pythonではほとんど必要がないためです。開発者の大多数にとっては、「まったく使用されていない」とおっしゃるとおりです。ただし、これらのインターフェース機能を本​​当に必要とする非常にニッチなケースがあることを認め、Pythonの作成者はそれを可能にする使いやすいAPIを提供しました。
David Culbreth

39

インターフェースは、Python 2.7およびPython 3.4以降をサポートし。

あなたがしなければならないインターフェイスをインストールするには

pip install python-interface

コード例:

from interface import implements, Interface

class MyInterface(Interface):

    def method1(self, x):
        pass

    def method2(self, x, y):
        pass


class MyClass(implements(MyInterface)):

    def method1(self, x):
        return x * 2

    def method2(self, x, y):
        return x + y

7
このライブラリーIMHOの主な利点は、それが与える初期の失敗です。クラスが指定されたインターフェースを正しく実装していない場合、クラスが読み込まれるとすぐに例外が発生します-使用する必要さえありません。 。Python独自の抽象基本クラスを使用すると、クラスを最初にインスタンス化するときに例外が発生します。
Hans

ABCは同様の組み込み機能を提供しているので不要です。
ダニエル

@DanielCasaresは、ABCが実際のインターフェースを提供するのですか、それとも、ABCが提供するソリューションが状態または実装のない抽象クラスであることを意味しますか?
asaf92

36

抽象基本クラスを使用したインターフェースの実装は、最新のPython 3でははるかに簡単であり、プラグイン拡張のインターフェースコントラクトとしての目的を果たします。

インターフェース/抽象基本クラスを作成します。

from abc import ABC, abstractmethod

class AccountingSystem(ABC):

    @abstractmethod
    def create_purchase_invoice(self, purchase):
        pass

    @abstractmethod
    def create_sale_invoice(self, sale):
        log.debug('Creating sale invoice', sale)

通常のサブクラスを作成し、すべての抽象メソッドをオーバーライドします。

class GizmoAccountingSystem(AccountingSystem):

    def create_purchase_invoice(self, purchase):
        submit_to_gizmo_purchase_service(purchase)

    def create_sale_invoice(self, sale):
        super().create_sale_invoice(sale)
        submit_to_gizmo_sale_service(sale)

オプションで、のように抽象メソッドに共通の実装を持たせ、上記のようにサブクラスcreate_sale_invoice()super()明示的に呼び出すことができます。

すべての抽象メソッドを実装していないサブクラスのインスタンス化は失敗します。

class IncompleteAccountingSystem(AccountingSystem):
    pass

>>> accounting = IncompleteAccountingSystem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class IncompleteAccountingSystem with abstract methods
create_purchase_invoice, create_sale_invoice

また、対応するアノテーションを次のように組み合わせることで、抽象プロパティ、静的メソッド、およびクラスメソッドを持つことができます。 @abstractmethodます。

抽象基本クラスは、プラグインベースのシステムを実装するのに最適です。クラスのインポートされたすべてのサブクラスにはを介してアクセスできる__subclasses__()ため、プラグインディレクトリからすべてのクラスをロードしimportlib.import_module()、それらが基本クラスをサブクラス化する場合は、それらを介して直接アクセスでき、すべてのクラス__subclasses__()に対してインターフェイスコントラクトが適用されていることを確認できます。インスタンス化中にそれら。

AccountingSystem上記の例のプラグイン読み込み実装は次のとおりです。

...
from importlib import import_module

class AccountingSystem(ABC):

    ...
    _instance = None

    @classmethod
    def instance(cls):
        if not cls._instance:
            module_name = settings.ACCOUNTING_SYSTEM_MODULE_NAME
            import_module(module_name)
            subclasses = cls.__subclasses__()
            if len(subclasses) > 1:
                raise InvalidAccountingSystemError('More than one '
                        f'accounting module: {subclasses}')
            if not subclasses or module_name not in str(subclasses[0]):
                raise InvalidAccountingSystemError('Accounting module '
                        f'{module_name} does not exist or does not '
                        'subclass AccountingSystem')
            cls._instance = subclasses[0]()
        return cls._instance

次に、AccountingSystemクラスを通じて会計システムプラグインオブジェクトにアクセスできます。

>>> accountingsystem = AccountingSystem.instance()

このPyMOTW-3投稿に触発されました。)


質問:モジュール名「ABC」は何を表していますか?
セバスチャンニールセン

「ABC」は「Abstract Base Classes」の略です。公式ドキュメントを
mrts

31

そこPython用のインターフェイスのサードパーティ製の実装は(最も人気がありますZopeのもで使用される、ツイスト)が、より一般的にPythonのプログラマーは、とのインタフェースを組み合わせた「抽象基本クラス」(ABC)、として知られている豊かな概念を使用することを好みますそこにもいくつかの実装面がある可能性。いろはは特によくはPython 2.6以降でサポートさ、参照されているPEPを、それでも以前のバージョンのPythonで、彼らは通常、「進むべき道」と見られている-ちょうどその方法のいくつかは、調達クラス定義NotImplementedErrorサブクラスがされるようにしますこれらのメソッドをオーバーライドした方がよいことに注意してください!-)


3
Python用のインターフェースのサードパーティ実装があります。それはどういう意味ですか?ABCについて説明していただけますか?
Pratik Deoghare、2010年

2
さて、私はABCが「より豊か」であることについて問題を取り上げます。;)zope.interfaceができることは、ABCが他の方法と同じようにできないことです。しかし、そうでなければ、あなたはいつものように正しいです。+1
Lennart Regebro 2010年

1
@Alfred:zope.interfaceのようなモジュールは標準ライブラリには含まれていませんが、pypiから入手できます。
Lennart Regebro、2010年

ABCのコンセプトを理解するのにまだ苦労しています。ABCの観点から誰かがtwistedmatrix.com/documents/current/core/howto/components.html(IMHO、インターフェースの概念の優れた説明)を書き換えることは可能でしょうか?それは意味がありますか?
mcepl

21

このようなもの(私がPythonを持っていないので機能しないかもしれません):

class IInterface:
    def show(self): raise NotImplementedError

class MyClass(IInterface):
    def show(self): print "Hello World!"

2
__init__(self)コンストラクターはどうすればよいですか?
Pratik Deoghare、2010年

1
あなた次第。抽象クラスからオブジェクトを構築することに対するコンパイル時のチェックがないため、コーディング/コンパイル中に保護を得ることができません。継承されるコンストラクターがあるため、オブジェクト作成され、「空」になります。これを可能にして後で失敗をキャッチすることでより良い結果を得るか、または例外をスローする同様のコンストラクターを実装してその場でプログラムを明示的に停止するかは、あなた次第です。
Bandi-T、

1
そのためabc.ABC、レイズよりもはるかに優れています。すべての抽象メソッドを実装していないサブクラスのNotImplementedErrorインスタンス化はabc.ABC早期に失敗するため、エラーから保護されます。エラーがどのように見えるかについては、以下の私の答えを参照してください。
mrts 2018

8

私の理解では、Pythonのような動的言語ではインターフェースは必要ありません。Java(またはその抽象基本クラスを備えたC ++)のインターフェースは、たとえば、一連のタスクを実行できる適切なパラメーターを渡していることを確認するための手段です。

たとえば、observerとobservableがある場合、observableはIObserverインターフェイスをサポートするオブジェクトのサブスクライブに関心があり、次にそれが notifyアクションをます。これはコンパイル時にチェックされます。

Pythonでは、compile time実行時にメソッド検索が実行されるようなものはありません。さらに、__ getattr __()または__getattribute __()マジックメソッドでルックアップをオーバーライドできます。言い換えると、オブザーバーとして、アクセス時にcallableを返すことができる任意のオブジェクトを渡すことができますnotify属性ます。

これは私に結論を導きます、Pythonのインターフェースは実際に存在します -それはそれらの施行がそれらが実際に使用される瞬間に延期されるだけです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.