任何数据的Python General Wrapper类

时间:2013-10-05 21:37:42

标签: python class wrapper

我想为任何数据编写一个通用的包装类。主要是我试图创建一个功能,如果它有一段时间没有被使用,将自动将数据存储在硬盘驱动器中(一种自动交换)。

我已经用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'

我当然知道我无法使用添加 radd 函数(只需使用+语法)。我这样做是为了看看世界上发生了什么:这是结果

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

很明显它会进入“添加”函数,然后进入第二个classe的添加函数,然后进入第一个类的“radding”函数,然后最终进入第二个类“radding”函数 - 什么世界正在发生什么? 此外,当另一个没有时,这个有用 - 我很困惑。

另外,如果你知道有任何代码,请告诉我!

2 个答案:

答案 0 :(得分:3)

当您a + b时,会拨打电话self.value.__add__(other)。由于a.value为10,因此会调用(10).__add__(b)。由于badder实例,因此整数10不知道如何将自身添加到b,因此它返回NotImplemented__radd__的{​​{1}}方法在此阶段尚未调用!由于您返回b的结果,因此您的self.value.__add__(other)方法也会返回NotImplemented。一旦发生这种情况,就会调用__add__,并且出于同样的原因返回b.__radd__(a) - 它会委托给NotImplemented,但失败了。由于两者都返回(12).__radd__(a),Python认为对象不知道如何相互添加,因此它会引发错误。

正如您所发现的,解决方案是使用NotImplemented而不是直接调用魔术方法。 (您无需为此单独创建课程;只需更改+课程即可调用adder而不是self.value + other等。)当您使用self.value__add__(other)时,你激活Python的内部机制,它在左操作数上调用+然后,如果不起作用,则在右操作数上调用__add__。当您直接呼叫__radd____add__时,您绕过了这个内部机制,只调用其中一个。这意味着您永远不会进入两个对象将其自身“减少”到其基础值的状态。相反,你尝试左手__radd__,当它失败时,你不会“退回”到__add__ ---你从__radd__开始再次失败你在第一部分所做的“降价”。

关键是__radd__知道如果10 + b失败就会致电b.__radd__(10),但如果你直接致电(10).__add__(b),它就不会知道(10).__add__(b) 1}},所以永远不会调用__radd__

答案 1 :(得分:1)

在Python中模拟数字类型(docs

评估表达式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__