我有一个包含一个或多个数字元素的类。
class Foo:
# ... other methods ...
def _update(self, f):
# ... returns a new Foo() object based on transforming
# one or more data members with a function f()
def __add__(self, k):
return self._update(lambda x: x.__add__(k))
def __radd__(self, k):
return self._update(lambda x: x.__radd__(k))
def __sub__(self, k):
return self._update(lambda x: x.__sub__(k))
def __rsub__(self, k):
return self._update(lambda x: x.__rsub__(k))
def __mul__(self, k):
return self._update(lambda x: x.__mul__(k))
def __rmul__(self, k):
return self._update(lambda x: x.__rmul__(k))
def __div__(self, k):
return self._update(lambda x: x.__div__(k))
def __rdiv__(self, k):
return self._update(lambda x: x.__rdiv__(k))
# I want to add other numeric methods also
有没有办法可以为所有numeric methods推广这一点,而不必为每一个都做这个?
我只想委托数值方法列表中的任何方法。
答案 0 :(得分:3)
你想在这里使用operator
module以及二进制数字运算符名称的(简短)列表,而没有紧凑的下划线:
import operator
numeric_ops = 'add div floordiv mod mul pow sub truediv'.split()
def delegated_arithmetic(handler):
def add_op_method(op, cls):
op_func = getattr(operator, op)
def delegated_op(self, k):
getattr(self, handler)(lambda x: op_func(x, k))
setattr(cls, '__{}__'.format(op), delegated_op)
def add_reflected_op_method(op, cls):
op_func = getattr(operator, op)
def delegated_op(self, k):
getattr(self, handler)(lambda x: op_func(k, x))
setattr(cls, '__r{}__'.format(op), delegated_op)
def decorator(cls):
for op in numeric_ops:
add_op_method(op, cls)
add_reflected_op_method(op, cls) # reverted operation
add_op_method('i' + op, cls) # in-place operation
return cls
return decorator
现在只需装饰你的班级:
@delegated_arithmetic('_update')
class Foo:
# ... other methods ...
def _update(self, f):
# ... returns a new Foo() object based on transforming
# one or more data members with a function f()
装饰器使用您想要委派调用的名称来使其更加通用。
演示:
>>> @delegated_arithmetic('_update')
... class Foo(object):
... def _update(self, f):
... print 'Update called with {}'.format(f)
... print f(10)
...
>>> foo = Foo()
>>> foo + 10
Update called with <function <lambda> at 0x107086410>
20
>>> foo - 10
Update called with <function <lambda> at 0x107086410>
0
>>> 10 + foo
Update called with <function <lambda> at 0x107086410>
20
>>> 10 - foo
Update called with <function <lambda> at 0x107086410>
0
答案 1 :(得分:2)
使用类装饰器:
def add_numerics(klass):
for numeric_fn in ['add','radd','sub','rsub','mul','rmul','div','rdiv']:
dunder_fn = '__{}__'.format(numeric_fn)
setattr(klass, dunder_fn, lambda self, k: self._update(lambda x: getattr(x, dunder_fn)(k)))
return klass
@add_numerics
class Foo:
def _update(self, f):
# ...
return Foo()
答案 2 :(得分:0)
这可能太一般,因为它将调度未明确声明的任何属性。
class Foo:
def _update(self, f):
...
def __getattr__(self, attr):
def __(self, k):
return self._update( lambda x: x.__getattr__(attr)(k) )
return __
你可以让它更有选择性:
def __getattr__(self, attr):
if attr in ['__add__', '__radd__', ... ]:
def __(self, k):
return self._update( lambda x: x.__getattr__(attr)(k) )
return __
else:
raise AttributeError("Unknown attribute: {0}".format(attr))