14

これは、特にPythonの性質を知っている人にとってはばかげた質問のように聞こえるかもしれませんが、私はただ疑問に思っていました。オブジェクトが「インターフェイスを実装する」かどうかを知る方法はありますか?

私が言いたいことの例を与えるために:

私がこの関数を持っているとしましょう:

def get_counts(sequence):
     counts = {}
     for x in sequence:
         if x in counts:
             counts[x] += 1
         else:
             counts[x] = 1
     return counts

私の質問は次のとおりです。関数に渡されるオブジェクトが正しいことを確認する方法はありiterableますか?JavaまたはC#では、特定のインターフェイスを実装する任意のオブジェクトをメソッドに受け入れさせることでこれを実行できることを知っています。たとえば、次のiIterableようにします。void get_counts(iIterable sequence)

私の推測では、Pythonでは、プリエンプティブなイントロスペクションチェックを使用しdecorator おそらく?)exception、オブジェクトに属性がない場合はカスタムをスローする必要があり__iter__ます。しかし、これを行うためのよりPython的な方法はありますか?

4

4 に答える 4

11

Python(2.6以降)には抽象基本クラス(別名仮想インターフェイス)があり、JavaまたはC#インターフェイスよりも柔軟性があります。オブジェクトが反復可能かどうかを確認するには、次を使用しますcollections.Iterable

if isinstance(obj, collections.Iterable):
    ...

ただし、elseブロックで例外が発生する場合、Pythonの最も答えは次のとおりです。チェックしないでください。適切なタイプを渡すのは発信者次第です。反復可能なオブジェクトを期待していることを文書化する必要があります。

于 2012-12-17T18:23:07.550 に答える
9

isinstance()またはインターフェースの前にポリモーフィズムとダックタイピングを使用する

通常、オブジェクトで何をしたいのかを定義してから、ポリモーフィズムを使用して各オブジェクトが実行したいことにどのように応答するかを調整するか、ダックタイピングを使用します。手元のオブジェクトが最初にやりたいことを実行できるかどうかをテストします。これは、呼び出しとイントロスペクションのトレードオフであり、従来の知識では、イントロスペクションよりも呼び出しの方が望ましいとされていますが、Pythonでは、テストよりもダックタイピングが優先されisinstanceます。

したがって、そもそも何かが反復可能であるかどうかをフィルタリングする必要がある理由を理解する必要があります。なぜあなたはこれを知る必要があるのですか?try: iter(object)、を使用しexcept TypeError: # not iterableてテストします。

または、渡されたものが反復可能でない場合は、エラーを通知するため、例外をスローする必要があります。

ABC

ダックタイピングでは、複数の方法をテストする必要がある場合があるため、isinstance()テストの方が適している場合があります。このような場合、Abstract Base Class(ABC)を使用することもオプションになる可能性があります。ABCを使用して、たとえば、特定の操作に適したタイプとして、いくつかの異なるクラスを「ペイント」しましょう。ABCを使用して、使用する特定の実装ではなく、実行する必要のあるタスクに焦点を当てましょう。あなたはPaintableABC、PrintableABCなどを持つことができます。

Zopeインターフェースとコンポーネントアーキテクチャ

アプリケーションが非常に多くのABCを使用している場合、またはさまざまな状況に対処するためにクラスにポリモーフィックメソッドを追加し続ける必要がある場合、次のステップは、 Zopeコンポーネントアーキテクチャなどの本格的なコンポーネントアーキテクチャの使用を検討することです。(ZCA)

zope.interfaceインターフェースは、特にZCAアダプターと組み合わせた場合、ステロイドのABCです。インターフェイスは、クラスの予想される動作を文書化します。

if IFrobnarIterable.providedBy(yourobject):
    # it'll support iteration and yield Frobnars.

ただし、アダプタを検索することもできます。クラスでシェイプを使用するたびにすべての動作を配置する代わりに、特定のユースケースにポリモーフィックな動作を提供するアダプターを実装します。オブジェクトを、印刷可能、反復可能、またはXMLにエクスポート可能に適合させることができます。

class FrobnarsXMLExport(object):
    adapts(IFrobnarIterable)
    provides(IXMLExport)

    def __init__(self, frobnariterator):
        self.frobnars = frobnariterator

    def export(self):
        entries = []
        for frobnar in self.frobnars:
            entries.append(
                u'<frobnar><width>{0}</width><height>{0}</height></frobnar>'.format(
                    frobnar.width, frobnar.height)
        return u''.join(entries)

コードは、各形状のアダプターを検索するだけです。

for obj in setofobjects:
    self.result.append(IXMLExport(obj).export())
于 2012-12-17T18:27:20.757 に答える
2

Pythonの方法は、ダックタイピングを使用し、「許可ではなく、許しを求める」ことです。これは通常、ブロック内で操作を実行し、tryそれが期待どおりに動作すると想定してから、exceptブロック内の他のケースを処理することを意味します。

于 2012-12-17T18:24:17.860 に答える
1

私はこれがコミュニティがあなたにそれをすることを勧める方法だと思います:

import sys

def do_something(foo):
    try:
        for i in foo:
            process(i)
    except:
        t, ex, tb = sys.exc_info()
        if "is not iterable" in ex.message:
            print "Is not iterable"

do_something(True)

または、のようなものを使用できますzope.interface

于 2012-12-17T18:27:11.630 に答える