2010-12-14 5 views
7

私は、最も単純なケースでは、アイテムの繰り返し可能な機能を持っています。異なるパラメータタイプを優雅に扱います

def foo(items): 
    for item in items: 
     # do stuff 

時々、私は直接それを項目の反復可能を渡したいのではなく、反復可能なを取得するためのメソッドを提供するオブジェクトはありません:

def foo(obj): 
    for item in obj.iteritems(): 
     # do same stuff as above 

私はこのように、これらの2例をマージすることができますが:

def foo(obj): 
    try: 
     items = obj.iteritems() 
    except ValueError: 
     items = obj 
    for item in items: 
     # do stuff 

これはうまくいきます。

def foo(objs): 
    for item in itertools.chain.from_iterable(obj.iteritems() for obj in objs): 
     # do same stuff again 

インターフェースに互換性がないので、私はまだ、try-exceptアプローチを使用することができます。今、私はこのようになります第三のユースケースを取得します。しかし、ネストされたtry catchは非常に醜いものになり始めます。さらに4番目のユースケースを追加したいときtryブロックをネストすることなくこれを解決する方法はありますか?

+1

ああ、私はPythonで適切な関数のオーバーロードがあったと思います! –

+3

@André:ほとんどの場合、Pythonでは、このような関数/メソッドのオーバーロードが必要な場合は、間違った方法で行います。 –

+0

しかし、iterableを明示的に送信するとどうなりますか?あまりにも冗長ですか? – tokland

答えて

2

現状では、あなたはおそらく、ここに第三の少なくとも2つのメソッドを使用する必要がありますちょうどitertools.chain.from_iterableの結果との最初の呼び出し。また、* argsのために潜在的に使用することもできます。あなたの正確なケースに依存します(実際の例を参考にしてください)。単純なヘルパー関数を使用して、正しいタイプのイテレータを返すこともできます。

おそらくこれはうまくあります:

def _foo_iter(obj): 
    try: 
     return obj.iteritems() 
    except AttributeError: 
     return obj 

def foo(*objs): 
    for obj in objs: 
     for item in _foo_iter(obj): 
+0

私が提供したコードは実際のものにかなり近く、名前だけが変更されています。 –

+0

@ Space_C0wb0y:あなたはそれをどれくらい正確に使っているのか、何のために説明していませんか?いくつかの事柄については、あなたには発生していないよりよい方法があるかもしれません。私はカスタム関数を使っていましたが、 'x in y'もちょうどいいでしょうが何らかの理由で私には起こっていませんでした) –

+0

関数はジェネレータであり、各アイテムの特定のプロパティを計算します。 –

0

オブジェクトが反復可能であるかどうかを確認するには、次の

import collections 
isinstance(obj, collections.Iterable) 

これは、あなたには、いくつかの問題を取り除く必要があります。

また、このような問題を処理する方法は、(それはしかし該当するかどうかわからない)再帰を使用することです:

def foo(obj): 
    if isinstance(obj, collections.Iterable): 
     for el in obj: 
      foo(el) 
    # now do stuff 
0

hasattr(object, name)

if hasattr(obj, '__iter__'): 
     return [o for o in obj] 
    elif hasattr(obj, 'iteritems'): 
     return [o for o in obj.iteritems()] 
    elif isinstance(obj, list) or isinstance(obj, tuple): 
     return [o.iteritems() for o in [o for o in obj]] 
    else: 
     raise TypeError 

class Bar(list): 
    def iteritems(self): 
     return self.__iter__() 

print foo([1,2,3]) 
print foo(Bar([1,2,3])) 
print foo([[1,2,3], [1,2,3]]) 
print foo(1) 

[1, 2, 3] 
[1, 2, 3] 
[[1, 2, 3], [1, 2, 3]] 
Traceback (most recent call last): 
    File "test.py", line 20, in <module> 
    print foo(1) 
    File "test.py", line 11, in foo 
    raise TypeError 
TypeError 
+0

'hasattr'は基本的に' getattr'のまわりで 'try'です。 –

+0

@chrisいいえ、例外をネストするなど強制的にネストすることはありません。何が問題なのですか? –

1

はクリスに同意する必要があります:魔法は理解し、すべての入力が振り向くとあなたを噛まないように起こっています。 iterableのiterableオブジェクトのiterableを渡すと、実際にデータを処理するレベルをどのように指定しますか?

「リストまたはジェネレータのいずれか」を入力として使用すると、関数の呼び出しが前処理されることがあります。

関連する問題