2

二項演算子(binop)として記述した関数があるとすると、任意の数の引数を取る複数演算子(multiop)に拡張するにはどうすればよいですか?ライブラリ( functoolsなど)にそのようなデコレータはありますか?

たとえば(デコレータにこの動作を提供してもらいたい):

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

mult(2,3,4) # 2*3*4 = 24
mult(7) # 7
mult(2,3) # 6

明らかに、私はデコレータについて言及せずに質問することはできません、この答え

私は自分で書いてみましたが、うまく機能させることができませんどこが間違っているのかについての説明も歓迎します。

def binop_to_multiop(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        if len(args) == 1: return args[0] # fails
        return f(args[0],(f(*args[1:], **kwds)), **kwds) #recursion attempt fails
    return wrapper

(さまざまな)を与えます。TypeError: mult() takes exactly 2 arguments (N given) N!=2

4

3 に答える 3

4

reduce()頭に浮かぶ:

from functools import wraps

def binop_to_multiop(binop):
    @wraps(binop)
    def multiop(x, *xs):
        return reduce(binop, xs, x)
    return multiop

# ...

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

print mult(2, 3, 4)
print mult(7)
print mult(2, 3)

結果:

$ python multiop.py
24
7
6
于 2012-09-24T22:57:50.580 に答える
3

自分でコード化しようとするあなたの試みは、ほとんど機能していませんでした。wrapper1 つを除くすべての引数を に渡すのではなく、再帰ステップを再帰的に変更する必要があるだけですf

def binop_to_multiop(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        if len(args) == 1: return args[0]
        return f(args[0], wrapper(*args[1:], **kwds), **kwds)
    return wrapper

ベースケースに問題はなかったので、コメントの内容がわかりません#fails

また、リストのどちらの終わりから解決を開始するかについても考慮する必要がある場合があります (つまり、演算子の結合性が左または右のどちらであるか)。掛け算や足し算のような演算子の場合は問題になりません(a+b)+c = a+(b+c)が、その他の場合は奇妙な結果になる可能性があります。たとえば、減算は期待どおりに機能しない場合があります。

@binop_to_multiop
def sub(a, b):
    return a - b

上記で定義されたデコレータを使用すると、sub(a, b, c)とは異なる結果が得られa-b-cます (a-(b-c)の代わりに行われます(a-b)-c)。同じように動作させたい場合は、次のようにデコレータを再定義して連想のままにすることができます (ほとんどのコンピューター言語でほとんどの数学演算子が行うように)。

def left_associative_binop_to_multiop(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        if len(args) == 1: return args[0]
        return f(wrapper(*args[:-1], **kwds), args[-1], **kwds)
    return wrapper

より洗練されたアプローチは、連想性をデコレーターのパラメーターにすることですが、パラメーターを必須にしたくない場合は注意が必要です。

于 2012-09-24T23:02:15.853 に答える
3
def binop_to_multiop(f):
    def wrapper(*args):
        return reduce(f, args) if args else None
    return wrapper

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

print mult(2,3,4)
print mult(7)
print mult(2,3)
print mult(4,5,6,7)

与える 24 7 6 840

于 2012-09-24T23:03:12.267 に答える