python-同时重载多个运算符

python-同时重载多个运算符,python,operator-overloading,Python,Operator Overloading,我有一个自定义类,我想重载几个Artimetic操作符,并想知道是否有一种方法可以避免为每个操作符单独编写代码。我还没有找到任何不显式重载每个运算符的示例 class Foo(object): a=0 def __init__(self, a): self.a=a def __add__(self, other): #common logic here return Foo(self.a+oth

我有一个自定义类,我想重载几个Artimetic操作符,并想知道是否有一种方法可以避免为每个操作符单独编写代码。我还没有找到任何不显式重载每个运算符的示例

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

但是像这样手动构造操作似乎有点愚蠢。这种方法有意义吗,还是有更好的方法

您可以通过反射和高阶函数来实现这一点,尽管这可能不适合继承

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)))
我只想使用模块:


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

例如


您必须定义方法。这是因为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
f=Foo(1) >>>g=Foo(3) >>>f*g?没有? 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 TypeError:不支持*:“Foo”和“Foo”的操作数类型 >>>getattr(f,'.'.''.'多'.) >>>f.uuu mul(g) >>>f.uuu mul_uuu(g).a 3.
你能做的“最好”是使用锑的溶液,这是最干燥的。

定义了一个装饰器
总排序
,我认为它符合你的要求,只适用于关系运算符。源代码并不太难,所以你可以很容易地调整它的行为。看看我对这个问题的回答中的MagicNumber类:谢谢,这绝对是一个改进。我想我更喜欢NPE答案的简单性,但我已经将它标记为正确,因为它回答了我提出的问题。谢谢
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