これが実用的なソリューションです。完全ではなく、かなり悪いデザインの選択でいっぱいですが、役に立てば幸いです.
class Expr(object):
def __init__(self, op, left, right):
self.op = op
self.left = left
self.right = right
def __call__(self, current):
l = self._replace_current(self.left, current)
r = self._replace_current(self.right, current)
return self._do_operation(l, r)
def _replace_current(self, val, current):
if val == 'current':
return current
elif isinstance(val, Expr): # recurse
return val(current)
else:
return val
def _do_operation(self, l, r):
if self.op == '+':
return l + r
elif self.op == '*':
return l * r
elif self.op == '-':
return l - r
def __add__(self, other):
return self._left_op('+', other)
def __radd__(self, other):
return self._right_op('+', other)
def __mul__(self, other):
return self._left_op('*', other)
def __rmul__(self, other):
return self._right_op('*', other)
def __sub__(self, other):
return self._left_op('-', other)
def __rsub__(self, other):
return self._right_op('-', other)
def _left_op(self, op, other):
if isinstance(other, Current):
return Expr(op=op, left=self, right='current')
else:
return Expr(op=op, left=self, right=other)
def _right_op(self, op, other):
if isinstance(other, Current):
return Expr(op=op, left='current', right=self)
else:
return Expr(op=op, left=other, right=self)
class Current(Expr):
def __init__(self):
super(Current, self).__init__(None, None, None)
def __call__(self, current):
return current
def _left_op(self, op, other):
return Expr(op=op, left='current', right=other)
def _right_op(self, op, other):
return Expr(op=op, left=other, right='current')
current = Current()
class YourObj(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __call__(self, **kw):
for key, val in kw.iteritems():
# You should probably make sure it is actually an attribute of YourObj
if isinstance(val, Expr):
current = self.a
new_val = val(current)
setattr(self, key, new_val)
else:
setattr(self, key, val)
そして、次のようなことができます:
obj = YourObj(a=4, b=5)
obj(a=current - 4 + current * current)
これは基本的に、Python の数学演算に組み込まれた式インタープリターです。
current
(+ のような)に対して演算を使用するときはいつでも、( andをExpr
オーバーライドするため) が返され、これがどの演算であるか、および各オペランドが何であるかを登録します。これらの式は入れ子にすることができるので、 と言えばを返します。__add__
__radd__
current + 4 - current
Expr(op='-', left=Expr(op='+', left='current', right=4), right='current')
式は、関数のように呼び出し、'current' を置き換える値を渡すことで評価できます。式を評価すると、次のようになります。
- 'current' のすべての出現箇所を渡された値で置き換えます
- ネストされた関数を再帰的に評価する
- 式全体の最終結果を返す
を実行するobj(a=current + 4)
と、 の__call__
メソッドYourObj
が呼び出されます。の結果の式を評価し、current + 4
に格納しa
ます。
これがより明確になることを願っています。混乱を避けるために、「現在」の名前を変更する必要があるかもしれません。