ここ。 からの素晴らしい質問(そしてたくさんの素晴らしい答え)に触発されました
「オブジェクトではなく、インターフェースに対するコード」というステートメントは、Pythonで何か意味がありますか?
元の質問 のような答えを探していますが、Pythonスニペットと考えがあります。
「オブジェクトではなくインターフェースに対するコード」は、Python言語にはインターフェース機能がないため、文字通り意味がありません。大まかな Python同等のものは「ダックタイピングを使用する」です。オブジェクトがダックであるかどうかを確認する場合、つまり、オブジェクトにquack()
メソッドがあるかどうかを確認する必要があります。 quack()
を試して適切なエラー処理を提供することをお勧めします。それがDuck
のインスタンスであるかどうかをテストするのではなく、.
Pythonの一般的なダックタイプは、ファイル(まあ、実際にはファイルのようなオブジェクト)、マッピング(dict
のようなオブジェクト)、呼び出し可能オブジェクト(関数のようなオブジェクト)、シーケンス(list
のようなオブジェクト)です。 、およびiterables(反復できるもの。コンテナーまたはジェネレーターの場合があります)。
例として、ファイルが必要なPython機能は、通常、必要なfile
のメソッドを実装するオブジェクトを受け入れます。file
クラスから派生する必要はありません。たとえば、標準のオブジェクトとして必要になるのは、write()
メソッド(そしておそらくflush()
とclose()
ですが、実際には必要ありません)同様に、callableは、__call__()
メソッドを持つオブジェクトです。関数タイプから派生する必要はありません(実際、関数タイプから派生することはできません)。
同様のアプローチを取る必要があります。オブジェクトを処理するために必要なメソッドと属性を確認してください。さらに良いことに、あなたが期待することを文書化し、あなたのコードを呼び出している人は誰でも完全な失敗ではないと仮定します。 (彼らがあなたにあなたが使うことができないオブジェクトを与えるならば、彼らは彼らが得るエラーから十分に速くそれを確かに理解するでしょう。)必要なときだけ特定のタイプをテストしてください。 is時々必要です。そのため、Pythonはtype()
、isinstance()
、およびissubclass()
、しかしそれらに注意してください。
Pythonのダックタイピングは、コードをオブジェクトの型に依存しすぎないように、つまり必要なインターフェイスがあるかどうかを確認するようにアドバイスされているという意味で、「オブジェクトではなくインターフェイスに対するコード」と同等です。違いは、Pythonでは、「インターフェイス」は、特にinterface
という名前の言語構造ではなく、特定の動作を提供するオブジェクトの属性とメソッドの非公式なバンドルを意味するだけです。
abc
モジュールを使用して、Python "interfaces"をある程度形式化できます。これにより、任意の基準を使用して、特定のクラスが特定の "abstract base class"(インターフェイス)のサブクラスであることを宣言できます。 「属性color
、tail_length
、およびquack
があり、quack
は呼び出し可能です。」など、必要に応じて指定します。ただし、これは、インターフェイス機能を備えた静的言語よりもはるかに厳密ではありません。
Pythonのインターフェースを理解するには、ダックタイピングを理解する必要があります。Python 用語集 :
duck-typing:オブジェクトのタイプを調べて適切なインターフェイスがあるかどうかを判断しないプログラミングスタイル。代わりに、メソッドまたは属性は単に呼び出されるか使用されます(「アヒルのように見え、アヒルのようにクワクワクする場合は、アヒルである必要があります。」)特定のタイプではなくインターフェイスを強調することにより、適切に設計されたコードは、多形置換。ダックタイピングは、type()またはisinstance()を使用したテストを回避します。 (ただし、ダックタイピングは抽象基本クラスで補完できることに注意してください。)代わりに、通常、hasattr()テストまたはEAFPプログラミングを使用します。
Pythonはインターフェースのコーディングを推奨していますが、強制されるのではなく、慣例によりです。 iterables、callables、ファイルインターフェイスなどの概念は、Python-だけでなく、map、filter、reduceなどのインターフェイスに依存するビルトインでも非常に普及しています。
インターフェースとは、特定のメソッドが存在し、オブジェクト間で標準化されることを期待することを意味します。これが、インターフェイスや抽象基本クラス、または検討したい実装のポイントです。
たとえば(Java)の場合、次のような対称暗号化のインターフェイスがあります。
public interface cipher
{
public void encrypt(byte[] block, byte[] key);
public void decrypt(byte[] block, byte[] key);
}
次に、それを実装できます。
public class aes128 implements cipher
{
public void encrypt(byte[] block, byte[] key)
{
//...
}
public void decrypt(byte[] block, byte[] key)
{
//...
}
}
次に、次のようにオブジェクトを宣言することができます。
cipher c;
ここで何をしましたか?さて、このオブジェクトc
を作成しました。このオブジェクトの型は、インターフェースの型と一致する必要があります。 c
はこのインターフェースに一致するものをすべて参照できるため、次の段階は次のようになります。
c = new aes128();
これで、cipher
に必要なメソッドを呼び出すことができます。
それがJavaです。これがPythonで行うことです:
class aes128(Object):
def __init__(self):
pass
def encrypt(self, block, key):
# here I am going to pass, but you really
# should check what you were passed, it could be
# anything. Don't forget, if you're a frog not a duck
# not to quack!
pass
これを使用したいが、渡されたオブジェクトが正しいかどうかわからない場合は、次のように使用してみてください。
c = aes128()
try:
c.encrypt(someinput, someoutput)
except:
print "eh? No encryption method?!"
ここでは、メソッドが存在する場合、渡されたものを処理できない場合は、c.encryptのraise
への実装に依存しています。もちろん、c
が文字列型であり、したがって必要な正しい型ではない場合、それも自動的にスローされ、(うまくいけば)キャッチします。
要するに、プログラミングの1つの形式は、インターフェイスルールに従わなければならないように入力され、もう1つは、それらを書き留める必要さえないということです。エラーが発生しなければ、機能したと信じているだけです。
それが2つの実際的な違いを示していることを願っています。
「オブジェクトではなく、インターフェースに対するコード」のPythonバージョンは何ですか?
適切な引用符は "実装ではなくインターフェイスに対するプログラム"です。この原理は、Pythonで、それが発生した言語であるSmalltalkで行ったのと同じように成り立ちます。
「オブジェクトではなく、インターフェースに対するコード」というステートメントを実行します。 Pythonで何か意味がありますか?
はい。 Pythonでも、この引用の元となった言語(Smalltalk)や他のすべての言語と同じ意味があります。