2

我有一个自定义类,我想重载几个算术运算符,想知道是否有一种方法可以避免为每个运算符单独编写代码。我无法找到任何不明确地逐个重载每个运算符的示例。

class Foo(object):
    a=0 

    def __init__(self, a):
        self.a=a            

    def __add__(self, other):
        #common logic here
        return Foo(self.a+other.a)

    def __sub__(self, other):
        #common logic here  
        return Foo(self.a-other.a)

    def __mul__(self, other):
        #common logic here
        return Foo(self.a*other.a)

#etc...

逻辑比这稍微复杂一些,但常见的模式是每个运算符重载方法都包含一些相同的代码来检查该操作是否被允许,然后使用类成员构造一个操作。我想减少冗余代码。这有效:

class Foo(object):
    a=0 

    def __init__(self, a):
        self.a=a            

    def operate(self, other, operator):
        #common logic here
        a = constructOperation(self.a, other.a, operator)
        return Foo(a)

    def __add__(self, other):
        return self.operate(other, "+")

    def __sub__(self, other):       
        return self.operate(other, "-")     


def constructOperation(operand0, operand1, operator):
    if operator=="+": 
        return operand0 + operand1
    if operator=="-": 
        return operand0 - operand1

但是像这样手动构建操作似乎有点愚蠢。这种方法是否有意义,或者这里有更好的方法吗?

4

4 回答 4

6

您可以通过反射和高阶函数来做到这一点,尽管这可能无法很好地与继承配合使用。

import operator

def apply_a(func):
    def inner(self, other):
        return Foo(func(self.a, other.a))
    return inner

class Foo(object):
    def __init__(self, a=0):
        self.a = a

for name in ['__add__','__mul__','__sub__']:
    setattr(Foo, name, apply_a(getattr(operator, name)))
于 2013-03-04T07:26:03.293 回答
5

我只会使用该operator模块:

import operator

class Foo(object):

    a=0 

    def __init__(self, a):
        self.a=a            

    def operate(self, other, op):
        #common logic here
        return Foo(op(self.a, other.a))

    def __add__(self, other):
        return self.operate(other, operator.add)

    def __sub__(self, other):       
        return self.operate(other, operator.sub)     
于 2013-03-04T07:28:29.447 回答
1

我不知道是否有办法避免定义所有(或至少大多数)运算符。没有一个是有道理的。毕竟,没有一种单一的方法来定义__sub__给定的__add__(和__mul__)。但是,一种改进是将可调用对象传递给constructOperation() 而不是符号运算符。

例如

class Foo(object):
    a=0 

    def __init__(self, a):
        self.a=a            

    def operate(self, other, operator):
        #common logic here
        a = constructOperation(self.a, other.a, operator)
        return Foo(a)

    def __add__(self, other):
        return self.operate(other, sum)

    def __sub__(self, other):       
        return self.operate(other, lambda x, y: x - y)     


def constructOperation(operand0, operand1, operator):
    return operator(operand0, operand1)
于 2013-03-04T07:29:33.553 回答
1

必须定义方法。这是因为 python 在调用特殊方法时会进行特殊查找,因此是这样的:

import operator

class Foo(object):

    def __init__(self, a):
        self.a = a
    def __getattr__(self, attr):
        try:
            func = getattr(operator, attr)
            return lambda x: Foo(func(self.a, x.a))
        except AttributeError:
            raise AttributeError(attr)

不起作用:

>>> f = Foo(1)
>>> g = Foo(3)
>>> f * g     #no __mul__?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'Foo' and 'Foo'
>>> getattr(f, '__mul__')
<function <lambda> at 0x2975140>
>>> f.__mul__(g)
<__main__.Foo object at 0x2922ed0>
>>> f.__mul__(g).a
3

您可以做的“最好”是使用锑的解决方案,这是最干燥的。

于 2013-03-04T07:32:33.883 回答