2011-05-25 12 views
1

私は自分が多くの関数を書いています。たとえば、コレクションの引数にx, y, ...などの引数を操作できるようにしたいと思います。 [(x1, y1, ...), (x2, y2, ...), ...]pythonデコレータは、単一のオブジェクトとコレクションオブジェクトをインテリジェントに操作できる機能を作成できますか?

このような関数を書くための明確でシンプルなデコレータ、パターン、またはテクニックがありますか?

ここでは、任意の例です:

def awesome(func): 
    # ??? 

@awesome 
def mult(a, b): 
    return a * b 

mult(3, 4)      # should return 12 
mult((3, 4))     # should return 12 or possibly (12,) 
mult(((3, 4), (2, 3), [3, 3])) # should return (12, 6, 9) 
mult([(3, 4), [4, 5]])   # should return (12, 20) 
+9

この機能に何が入り込んでいるのかわからないので、全体のアイデアはあまり良くありません。そのため、バグを見つけにくくなります。 '(xulのxul(x)in xs)' –

+0

yupと入力すれば意味があります。アップ。 –

+0

ダブタイピングと演算子のオーバーロードだけを使用するのはなぜですか?はるかに直感的で無臭であるようです。 – Pwnna

答えて

2

のPython 3.4は、異なる引数の型と同じ機能を呼び出すときに異なる動作を実装する簡単な方法を提供し、@singledispatchデコレータでsingle-dispatch generic functionsを紹介します。例えば、反復可能オブジェクトを受け入れるためにあなたのmult()機能できるようにする:あなたの関数の

from functools import singledispatch 
from collections.abc import Iterable 

@singledispatch 
def mult(a, b): 
    return a * b 

@mult.register(Iterable) 
def _(it): 
    return [mult(a, b) for a, b in it] 

「をベース」バージョンは、一般的な機能に変換し、@singledispatchで飾られています。次に、関数_()は、反復可能な要素の各要素に対してmult()を呼び出し、@mult.register()という汎用関数に登録されるように定義されています。上記の例では、最大一般性のためにcollections.abc.Iterableを使用するが

は、複数のコンクリートタイプの関数を登録することも可能です:

@mult.register(list) 
@mult.register(tuple) 
def _(it): 
    return [mult(a, b) for a, b in it] 

は、上記の技術を使用して、それが変換デコレータ@takes_iterableを書き込むことが可能です任意の汎用関数に関数、及び適切イテレート可能オブジェクトを処理するように別の関数を登録:

def takes_iterable(func): 
    generic = singledispatch(func) 
    @generic.register(Iterable) 
    def _(it): 
     return [func(*args) for args in it] 
    return generic 

@takes_iterable 
def mult(a, b): 
    return a * b 

使用例:

>>> mult(17,23) 
391 
>>> mult([(11, 29), (13, 23), (17, 19)]) 
[319, 299, 323] 

CAVEAT:コメントでBlckknghtで指摘したように、あなたは「シングル」モードで実行することを意図@takes_iterableで飾られた関数を呼び出した場合、予期しない結果を得るが、それにはどうなるの引数を渡します文字列のように繰り返し可能です。

実際には、ここで概説した実装ではなく、質問で要求される動作に固有のあいまいさの結果ですが、この手法を使用するかどうかを検討する際には留意する価値があります。

+0

これには、文字列が繰り返し可能であるという複雑さがあります。したがって、元の関数が引数として単一の文字列を取る場合、 'func(" abc ")'が単一の呼び出しであるか3つの関数が 'func(" a ")を呼び出すべきかをコードが指示する方法はありません。 func( "b"); func( "c") '。 – Blckknght

+0

@Blckknghtこれは良い点です(Jochen Ritzelの[comment](http://stackoverflow.com/questions/6128227/can-a-python-decorator-make-a-functionable-to-operate-on-単一オブジェクトとcol/24111648?noredirect = 1#comment7111301_6128227)上記)。私はその旨を警告で答えを更新しました。 –

関連する問題