私はいくつかの人々にデコレータの有用性を実証したかったのですが、単純な例では失敗しました。引数を持たない2つの関数f
とg
を考えてみましょう。 f()+ g()を返す関数として、その和f + gを定義することができます。もちろん、関数の追加、減算などは一般的に定義されていません。しかし、すべての関数を追加可能な関数に変換するデコレータを書くのは簡単です。なぜこの "実行可能な関数"のPython実装が失敗しますか?
ここでは、任意の関数を "操作可能な"関数、つまり標準モジュールoperator
の任意の演算子について前述の方法で動作する関数に変換するデコレータを使用したいと考えています。次のように私の実装が見えます:
import operator
class function(object):
def __init__(self, f):
self.f = f
def __call__(self):
return self.f()
def op_to_function_op(op):
def function_op(self, operand):
def f():
return op(self(), operand())
return function(f)
return function_op
binary_op_names = ['__add__', '__and__', '__div__', '__eq__', '__floordiv__', '__ge__', '__gt__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__or__', '__pow__', '__sub__', '__truediv__', '__xor__']
for name in binary_op_names:
type.__setattr__(function, name, op_to_function_op(getattr(operator, name)))
はのは、それが動作するかどうかを確認するために少しテストを実行してみましょう:
@function
def a():
return 4
def b():
return 7
c = a + b
print c()
print c() == operator.__add__(4, 7)
は出力:
11
True
これは、私はいくつかの実験の後に得た最終版であります。 は、今度は私が試したどのような顔をしているために、2つの小、無関係な修正をやらせる前に:
まず:binary_op_names
の定義では、丸括弧に角括弧を変更します。突然、完全に無関係のエラーメッセージが出てきます。
Traceback (most recent call last):
File "example.py", line 30, in <module>
c = a + b
TypeError: unsupported operand type(s) for +: 'function' and 'function'
これはどこから来ましたか?
第二:これは私には見えます
3
False
True
:出力
@function
def a():
return 4
def b():
return 7
c = a + b
print c()
print c() == operator.__add__(4, 7)
print c() == operator.__xor__(4, 7)
:ややより複雑なテストケースを実行し
op = getattr(operator, name)
type.__setattr__(function, name, lambda self, other: function(lambda: op(self(), other())))
:ラムダ式としてop_to_function_op
を書きますスコープのような漏れが、再び私はドンなぜこれが起こるのか理解していない。
タイプ.__ setattr__は悪何かをするようですが...ドン何を知っているの?タプルするためのリストは本当に奇妙です。タイプを変更した場合。setattrへの__setattr__はすべて動作するようです。 – mkorpela
典型的な 'memoize'デコレータはフィボナッチシーケンスに適用され、他のキャッシュに優しい問題はデコレータのデモンストレーションのためのより良いアプリケーションかもしれません。 – Daenyth
タプルの問題は厄介なバグのようです。私は同じ行動を見ている。 'name'に関するすべてのことは絶対にチェックアウトしますが、' type .__ setattr__'は動作しません。 – Nate