python - 同时重载多个运算符

3 投票
4 回答
1481 浏览
提问于 2025-04-17 17:50

我有一个自定义的类,想要重载几个数学运算符,但我在想有没有办法避免一个一个写代码。我找不到不需要逐个重载每个运算符的例子。

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 个回答

1

我不知道有没有办法避免定义所有(或者至少大部分)运算符。这样做是有道理的,毕竟,给定 __add__(加法)和 __mul__(乘法),并没有一种唯一的方法来定义 __sub__(减法)。

不过,有一个改进的建议是,可以把可调用的函数传递给 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)
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)     
7

你可以通过反射和高阶函数来实现这个功能,不过这样做可能和继承不太兼容。

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)))

撰写回答