3

1 つ以上の数値要素を含むこのようなクラスがあります。

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

すべての数値メソッドに対してこれを一般化する方法はありますか?

数値メソッドのリスト内の任意のメソッドを委任したいだけです。

4

3 に答える 3

3

operatorここでモジュールを、コンパクトにするためにアンダースコアなしで、2 進数の数値演算子名の (短い) リストと共に使用します。

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
于 2013-05-22T18:36:00.777 に答える
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()
于 2013-05-22T18:34:06.937 に答える
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))
于 2013-05-22T18:36:38.630 に答える