Python Magic Method增强分配误解

时间:2014-01-07 16:45:58

标签: python class methods

我正在创建一个简单的角度对象,它是最简单的形式,是一个整数值,当它超过360(回到0)或低于0(回到360)时会重现。我实现了增强赋值的魔术方法,但出于某种原因,这种方法无效。

class Angle:

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

    def __add__(self, other):
        """Check for recursion, then return the added value."""
        val = self.angle + other
        while val > 360:
            val -= 360
        while val < 0:
            val += 360
        return val

    def __radd__(self, other):
        """Reflected addition."""
        return self.__add__(other)

    def __iadd__(self, other):
        """Augmented addition assignment."""
        val = self.__add__(other)
        self.angle = val

它为self.angle,=分配一个非类型值。在我看来它应该工作,因为self.__add__()返回其他添加到self.angle的值,那么为什么不将val赋给self.angle?

4 个答案:

答案 0 :(得分:1)

完全删除__iadd__方法。

这将使+=运算符回退到__add__,这是对不可变类型进行建模的对象的首选行为。

示例:

class Angle(int):
    def __init__(self, val):
        self.val = val % 360
    def __add__(self, other):
        return Angle(self.val + other)
    def __sub__(self, other):
        return Angle(self.val - other)
    def __neg__(self):
        return Angle(-self.val)
    def __repr__(self):
        # just for demonstration purposes ok
        return str(self.val)

让我们尝试一下......

>>> a = Angle(35)
>>> a
35
>>> a + 400
75
>>> a
35
>>> a += 400
>>> a
75
>>> a - 75
0
>>> a - 76
359
>>> a
75
>>> a -= 76
>>> a
359

不需要__iadd____radd__,让python为你处理魔法。

答案 1 :(得分:1)

关于__iadd__(和其他__iXXX__方法):

  

这些方法应该尝试就地进行操作(修改   self)并返回结果(可能是,但不一定是,   自)。

您的__iadd__方法没有“为self.angle分配非类型”,它返回None(函数没有显式返回时的默认值),并重新绑定您当前的名称至None,即:

class Foo(object):
    def __init__(self, angle=120):
        self.angle = angle

    def __add__(self, other):
        """Check for recursion, then return the added value."""
        print "Foo.add"
        val = self.angle + other
        while val > 360:
            val -= 360
        while val < 0:
            val += 360
        return val


    def __iadd__(self, other):
        """Augmented addition assignment."""
        print "Foo.iadd"
        val = self.__add__(other)
        self.angle = val


f = Foo()
f += 20

print f is None

简而言之:您希望__iadd__返回有意义的内容,最有可能self

答案 2 :(得分:1)

__add____iadd__都应return Angle个对象:

class Angle(object):
    def __init__(self, angle):
        self.angle = angle % 360
    def __add__(self, other):
        return Angle(self.angle + other.angle)
    def __iadd__(self, other):
        return self.__add__(other)

请注意使用angle % 360来保留angle in range(0, 360)

答案 3 :(得分:0)

您需要return self实施__iadd__,因为__iadd__的返回值已分配到+=运算符的左侧。这就是Python文档中关于就地运算符实现的内容:

  

这些方法应该尝试就地进行操作(修改self)并返回结果(可能是,但不一定是自己)。

source