1

我想为任何数据编写一个通用包装类。首先,我正在尝试制作一个功能,如果它有一段时间没有使用,它将自动将数据存储在硬盘驱动器中(一种自动交换)。

我已经用 python 编程多年了,但我就是找不到一种“pythonic”的方式来做这件事。我最终求助于一个脚本,它可以为我编写所有可能的方法——但即使这样也没有奏效。看看下面。

我什至无法让这个简单的代码工作——为什么???

class adder(object):
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        print 'adding'
        return self.value.__add__(other)

    def __radd__(self, other):
        print 'radding'
        return self.value.__radd__(other)

a = adder(10)
b = adder(12)
print a + b 

输出

adding
Traceback (most recent call last):
  File "/home/user/Projects/CloudformDesign/PythonCloudform/cloudtb/playground/adding_classes.py", line 42, in <module>
    print a + b 
TypeError: unsupported operand type(s) for +: 'adder' and 'adder'

我当然知道我不能使用addradd函数(只需使用 + 语法)。我这样做是为了看看世界上正在发生什么:这是结果

class adder2(object):
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        print 'a2'
        return self.value + other

    def __radd__(self, other):
        print 'ra2'
        return other + self.value

a = adder(adder2(10))
b = adder(adder2(12))

print a + b

输出:

adding
a2
radding
ra2
22

很明显,它是进入“adding”函数,然后进入第二类的adding函数,然后进入第一类的“radding”函数,最后进入第二类的“radding”函数——在WORLD中是什么正在发生???此外,这在另一个没有的情况下有效——我很困惑。

另外,如果您知道任何执行此操作的代码,请告诉我!

4

2 回答 2

3

当你这样做时a + b,它会调用 call self.value.__add__(other)。由于a.value是 10,因此调用(10).__add__(b). 由于b是一个adder实例,整数 10 不知道如何将自己添加到b,所以它返回NotImplemented。在这个阶段不调用的__radd__方法!b由于您返回 的结果self.value.__add__(other),因此您的__add__方法也返回 NotImplemented。一旦发生这种情况,b.__radd__(a)就会被调用,并且NotImplemented出于相同的原因返回 --- 它委托给(12).__radd__(a),但失败了。由于两者都 return NotImplemented,Python 认为对象不知道如何相互添加,因此会引发错误。

正如您发现的那样,解决方案是使用+而不是直接调用魔术方法。(您不需要为此创建一个单独的类;只需将您的adder类更改为 callself.value + other而不是self.value__add__(other)等。)当您使用 时+,您会激活 Python 的内部机制,它会调用__add__左操作数,然后,如果没有t 工作,调用__radd__正确的操作数。当你直接调用__add__and__radd__时,你绕过了这个内部机制,只调用了两者之一。这意味着您永远不会达到两个对象都将自己“还原”到其基础值的状态。相反,你尝试左手__add__,当它失败时,你不会“退回”到__radd__——你从头开始__radd__,失去了你在第一部分所做的“价值减少”。

关键是如果失败就10 + b知道调用,但是如果你只是直接调用,它不知道任何关于的,所以永远不会调用。b.__radd__(10)(10).__add__(b)(10).__add__(b)__radd__b.__radd__(10)

于 2013-10-05T21:46:42.693 回答
1

在 Python 中模拟数字类型(文档

当表达式a + b被计算时,首先a检查一个__add__实现;如果有,a.__add__(b)则执行。如果没有,或者运行a.__add__(b)返回特殊值NotImplemented,则b检查__radd__实现;如果它没有或返回NotImplemented,则不能添加它们。

您的代码中发生了什么

提醒我们的对象:

>>> a = adder(adder2(10))
>>> a.value
adder2
>>> a.value.value
10

>>> b = adder(adder2(12))
>>> b.value
adder2
b.value.value
12

print a + b可以描述为:

a.__add__(b)                    which adder.__add__ implements as
a.value.__add__(b)              which adder2.__add__ implements as
a.value.value + b               so first we try
a.value.value.__add__(b)        but int.__add__ fails (returns NotImplemented) so we try
b.__radd__(a.value.value)       which adder.__radd__ implemented as
b.value.__radd__(a.value.value) which adder2.__radd__ implements as
a.value.value + b.value.value   which int.__add__ implements as addition

该怎么办

我认为您正在尝试创建一种可以添加到数字或其类型的其他对象的类型。如果是这样,你想要

class Adder(object):
    def __init__(self, value):
        self.value
    def __add__(self, other):
        return self.value + other
    def __radd__(self, other):
        return self.value + other

这相当于没有的版本+

class Adder(object):
    def __init__(self, value):
        self.value
    def __add__(self, other):
        r = self.value.__add__(other)
        if r is NotImplemented:
            r = other.__radd__(self.value) # so if other is a adder, use its __radd__ 
        return r                           # since our value's __add__ will return
    __radd__ = __add__
于 2013-10-05T21:44:47.250 回答