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!'
これはいい考えですか??あなたの答えに例を挙げてください。
ここで他の人が言及したように:
Pythonではインターフェイスは必要ありません。これは、Pythonには適切な多重継承があり、ダックタイピングもあるためです。つまり、mustの場所にJavaのインターフェイスがあり、Pythonにそれらを持っている必要はありません。
とはいえ、インターフェースにはまだいくつかの用途があります。それらのいくつかは、Python 2.6で導入されたPythonの抽象基本クラスでカバーされています。インスタンス化できない基本クラスを作成したいが、特定のインターフェースまたは実装の一部を提供したい場合に便利です。
別の使用法は、オブジェクトが特定のインターフェイスを実装することを何らかの方法で指定したい場合で、サブクラス化することでABCも使用できます。もう1つの方法はzope.interfaceです。これは、Zopeコンポーネントアーキテクチャの一部であるモジュールであり、非常に優れたコンポーネントフレームワークです。ここでは、インターフェイスからサブクラス化するのではなく、クラス(またはインスタンス)をインターフェイスの実装としてマークします。これは、コンポーネントレジストリからコンポーネントを検索するためにも使用できます。超クール!
抽象基本クラスに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()
Pythonのインターフェイスのサードパーティの実装があります(最も一般的なのは Zope's 、 Twisted でも使用されます)が、より一般的にはPythonコーダーは、「抽象基底クラス」(ABC)として知られるより豊かな概念を使用することを好みます。これは、インターフェースを実装側面を持つ可能性と組み合わせます。 ABCはPython 2.6以降で特によくサポートされています。 the PEP を参照してください。ただし、以前のバージョンのPythonでも、通常は「方法サブクラスがそれらのメソッドをオーバーライドした方がよいことに気づくように、メソッドのいくつかがNotImplementedError
を上げるクラスを定義するだけです!-)
インターフェース は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
このようなもの(周りにPythonがないのでうまくいかないかもしれません):
class IInterface:
def show(self): raise NotImplementedError
class MyClass(IInterface):
def show(self): print "Hello World!"
現代の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の投稿 に触発されました。)
私の理解では、Pythonのような動的言語ではインターフェースはそれほど必要ではありません。 Java(またはC++とその抽象基本クラス)インターフェースは、たとえば一連のタスクを実行できる適切なパラメーターを渡します。
例えば。オブザーバーとオブザーバブルがある場合、オブザーバブルはIObserverインターフェイスをサポートするオブジェクトのサブスクライブに関心があり、そのオブジェクトにはnotify
アクションがあります。これはコンパイル時にチェックされます。
Pythonでは、compile time
のようなものはなく、メソッド検索は実行時に実行されます。さらに、__ getattr __()または__getattribute __()マジックメソッドを使用してルックアップをオーバーライドできます。つまり、notify
属性にアクセスするとcallableを返すことができるオブジェクトをオブザーバーとして渡すことができます。
これにより、Pythonのインターフェース存在する-実際に使用される瞬間にそれらの実施が延期されるという結論に至ります。