動的型付けのため、Python で (Java や C# のように) インターフェイスの概念を必要としないのですか?
9 に答える
interface
as a キーワードおよびアーティファクトは、Java 1 によって導入され( C # はそこから取り入れられました)、オブジェクトが従わなければならないコントラクトを記述します。
しかし、インターフェースは常にオブジェクト指向パラダイムの重要な部分であり、基本的にはオブジェクトが応答する必要があるメソッドを表しています。Java は、静的な型チェックを提供するためにこのメカニズムを強制するだけです。
したがって、動的 (OO) プログラミング言語は、静的にチェックしないにもかかわらず、インターフェイスを使用します。Ruby などの他のデータ型と同様に、次のようになります。
@i = 1;
i
タイプを宣言する必要はありませんFixNum
。それを使用するだけです。インターフェイスについても同じことが言えます。それらはただ流れるだけです。トレードオフは、静的チェックを行うことができず、実行時にのみエラーが表示されることです。
一方、Go や Scala などの言語で使用される構造型(または私が呼ぶところの静的ダック型 :P ) は、両方の長所を提供します。
interface
1. CORBAキーワード
に関する Daniel Earwicker のコメントを参照してください。
必須ではありませんが、サポートしています。Zope Interfaces (Zope の外部で使用でき、使用されます) を確認してください。
多くの人が最初の応答として言うこととは反対に、インターフェースは「クラスがサポートするメソッド」を文書化する以上のことを行うために使用できることに注意してください。Grzenioは、「同じ動作を実装する」という彼の言葉でこれに触れています。この具体例として、JavaインターフェースSerializableを見てください。メソッドを実装していません。むしろ、クラスを安全にシリアル化できることを示す「マーカー」として使用されます。
このように考えると、インターフェースを使用する動的言語を使用するのが妥当かもしれません。そうは言っても、注釈に似たものがより合理的なアプローチかもしれません。
明示的なインターフェースを少し厄介にする少なくともいくつかの動的言語に関する重要なことの1つは、動的言語は、メソッドの作成などを行っても、事前に知らないメッセージ(エラー、「メソッド呼び出し」)に応答することが多いということです。急いで。オブジェクトがメッセージに正しく応答するかどうかを知る唯一の実際の方法は、オブジェクトにメッセージを送信することです。動的言語では、静的型チェックよりもそのようなことをサポートできる方がよいと考えているため、これで問題ありません。オブジェクトは、そのプロトコルに参加できることが「知られている」ため(たとえば、別のメッセージによって与えられるため)、特定のプロトコルで使用可能であると見なされます。
Perlにはロール(または特性)があります。これは、Java perlロールとは異なり、インターフェース以上のものです。perlロールの詳細については、これらのリンクを実装で確認できます。
インターフェイスは静的に型付けされた言語で使用され、それ以外は独立している 2 つのオブジェクトが「同じ動作を実装する」ことを記述します。動的型付け言語では、2 つのオブジェクトが同じ名前/パラメーターを持つメソッドを持っている場合、同じことを行うと暗黙的に想定しているため、インターフェイスは役に立ちません。
インターフェイス構造は、静的に型付けされた言語で使用され、特定のメソッド呼び出しコンテキストでどのオブジェクトを相互に置換できるかを型システムに教えます。2 つのオブジェクトが同じメソッドを実装しているが、共通の基本クラスからの継承または共通のインターフェイスの実装によって関連付けられていない場合、一方を他方に置き換えると、型システムはコンパイル時にエラーを発生させます。
動的言語は「ダックタイピング」を使用します。つまり、メソッドは実行時に単純に検索され、正しいシグネチャで存在する場合はそれが使用されます。そうしないと、実行時エラーが発生します。2 つのオブジェクトの両方が同じメソッドを実装して「アヒルのように鳴く」場合、それらは代用可能です。したがって、言語が基本クラスまたはインターフェイスを介してそれらを関連付ける明示的な必要はありません。
そうは言っても、動的な世界では概念としてのインターフェイスは依然として非常に重要ですが、多くの場合、ドキュメントで定義されているだけで、言語によって強制されていません。ときどき、プログラマーが実際に、この目的のためにインターフェイスをスケッチする基本クラスを作成するのを目にします。これはドキュメントを形式化するのに役立ち、インターフェイスの一部をインターフェイスの残りの部分に関して実装できる場合に特に役立ちます。
動的言語はダックタイピングです
アヒルのように歩き、アヒルのように鳴くなら、それはアヒルでなければなりません
http://en.wikipedia.org/wiki/Duck_typing
つまり、Delete()メソッドをサポートするオブジェクトを期待する場合は、
obj.Delete()
メソッドですが、オブジェクトがDelete()をサポートしていない場合、ランタイムエラーが発生します。静的に型付けされた言語はそれを許可せず、コンパイル時エラーをスローします。したがって、基本的には、開発時間と柔軟性の向上に対してタイプの安全性をトレードします。
インターフェイスがなければ、静的言語でそのようなことを行うことができます。
void Save(MyBaseClass item)
{
if (item.HasChanges)
item.Save()
}
ただし、これには、このメソッドに渡すすべてのオブジェクトがMyBaseClassから継承する必要があります。JavaまたはC#は、柔軟性の低いマルチ継承をサポートしていないため、クラスがすでに別のクラスを継承している場合は、MyBaseClassからも継承できないためです。したがって、ISavableインターフェイスを作成し、それを入力パラメーターとして受け入れて、アイテムを確実に保存できるようにすることをお勧めします。次に、タイプの安全性と柔軟性の両方の長所があります。
public interface ISavable
{
bool HasChanges {get;set;}
void Save();
}
void Save(ISavable item)
{
if (item.HasChanges)
item.Save()
}
最後のバックドアは、saveメソッドを使用してインターフェースを実装するすべてのアイテムを期待できない場合に、オブジェクトをパラメーターとして使用することです。
void Save(object item)
{
if (item.HasChanges)
item.Save()
}
ただし、繰り返しになりますが、コンパイル時のチェックがなく、互換性のないクラスでメソッドを使用すると、ランタイムエラーが発生する可能性があります。
C# と Java では、インターフェイスは、すべての抽象メソッドを持つ単なる抽象クラスです。それらは、本格的な多重継承を実際にサポートせずに疑似多重継承を可能にし、多重継承が生み出すあいまいさを実現するために存在します。
Python は多重継承をサポートしており、メソッドが複数の親に存在する場合にどの親のメソッドを呼び出すかを決定する独自の方法があります。