2016-11-06 5 views
1

1つのパラメータ、つまりの反復可能関数を入力とし、iterableに対して複数回繰り返したいとします。可能な限りイテレータをリストに変換しないようにする

私はこのようにそれを記述する場合:

def a_function(an_iterable): 
    for x in an_iterable: 
     print(x) 
    for x in an_iterable: 
     print(x) 

第二のループは、実行するか、しないかことがあります。反復可能カスタムジェネレータ関数またはf=open("file")を用いて得られたファイル・オブジェクト(のため

  • 自体をしない再装備/ジェネレータ機能をイテレータれないlistsetdict、またはrangeある場合、それが実行され

    • )。もちろん(ファイルイテレータの再利用は、ここでSOでの多くの質問の主題である)

    必要でない場合、私は不要なlistを作成しないようにこれを行うことができます:

    働くだろう
    def a_function(an_iterable): 
        if any(lambda x : type(an_iterable==x) for x in (range,list,set,dict))): 
         # use as-is 
         pass 
        else: 
         an_iterable = list(an_iterable) 
    
        for x in an_iterable: 
         print(x) 
        for x in an_iterable: 
         print(x) 
    

    多くの一般的なケースではありますが、一般的なケースではありません。

    繰り返し可能なオブジェクトに対して何度も繰り返し処理できるかどうかを検出するきれいな方法はありますか?

  • 答えて

    1

    あなたは反復可能で、実際のシーケンスであるかどうかを確認するためにcollections.abc.Sequenceクラスを使用することができます。

    >>> from collections.abc import Sequence 
    >>> isinstance([1,2,3], Sequence) 
    True 
    >>> isinstance((1,2,3), Sequence) 
    True 
    >>> isinstance(range(10), Sequence) 
    True 
    >>> isinstance(iter((1,2,3)), Sequence) 
    False 
    

    セットのためのこの文句を言わない仕事:

    >>> isinstance({1,2,3}, Sequence) 
    False 
    

    は、あなたがセットとのマッピング使用を含めたい場合はcollections.abs.Setおよびcollections.abc.Mapping

    >>> isinstance({1,2,3}, (Sequence, Set, Mapping)) 
    True 
    

    あなたは、必要に応じて配列を反復可能に変換するヘルパー関数を作成することもできます。

    def sequencify(iterable): 
        if isinstance(iterable, (Sequence, Set, Mapping)): 
         return iterable 
        return list(iterable) 
    

    をそして今、あなただけで行うことができます。

    def a_function(iterable): 
        iterable = sequencify(iterable) 
    
        for x in iterable: 
         print(x) 
        for x in iterable: 
         print(x) 
    

    をシンプルな代替がチェックすることです

    >>> hasattr([1,2,3], '__next__') 
    False 
    >>> hasattr(iter([1,2,3]), '__next__') 
    True 
    
    :その iterable引数が __next__メソッドを持っていません

    よく実装されたコンテナは反復可能であり反復自体ではないため、反復を進める方法の__next__を持つ反復子を返す__iter__メソッドしかありません。

    これはにつながる:

    def sequencify(iterable): 
        if not hasattr(iterable, '__next__'): 
         return iterable 
        return list(iterable) 
    

    最終選択肢が最も簡単です:シーケンスとして引数を文書化し、ない反復可能、ユーザーが提供する責任があるしましょう正しいタイプ。

    +0

    別の精度:私は 'yield'を使用して関数を作成する場合はどのような

    >>> l = [1, 2, 3, 4] >>> it = iter(l) >>> hasattr(l, '__next__') False >>> hasattr(it, '__next__') True 

    __next__がある場合は、あなたがそれが呼び出し可能であることを確認する必要があります属性?それには '__next__'はありませんが、「元に戻す」ことはできません。それは特別な場合ですか? 'hasattr(it、" __ code __ ")' –

    +0

    @ Jean-FrançoisFabreが 'callable'であるかどうかを確認するだけで確認できますか?問題はあなたがそれを呼び出すためのパラメータを知らないということです... – Bakuriu

    +0

    もちろん!その後は起こり得ません。ありがとう。 –

    0

    オブジェクトに__next__()メソッド(Python 3)、またはnext()メソッド(Python 2)があるかどうかを確認できます。そうであれば、それがイテレータプロトコルを実装していると仮定し、その値を再利用することはできません。

    >>> hasattr(l, '__next__') and callable(l.__next__) 
    False 
    >>> hasattr(it, '__next__') and callable(it.__next__) 
    True 
    
    関連する問題