`self [key] + = value`的魔术方法?

时间:2016-04-02 09:06:34

标签: python containers sequence magic-methods augmented-assignment

对于序列类型,赋值__setitem__有一个Python魔术方法=在容器级别是否有增强赋值+=的神奇方法?该操作似乎优雅地分解为item-type的增强赋值。这是合乎逻辑的。但是对于其他几乎所有东西来说都是一种神奇的方法,我认为在序列类型上应该有一组这些运算符的方法。我错过了吗?

应用程序是一种数据库。考虑使用SELECT实现__getitem__并使用INSERT实现__setitem__。 UPDATE应该有类似__additem__等的内容,对吗?

from __future__ import print_function
class Item(object):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return "Item " + str(self.value)
    def __iadd__(self, other):
        print("Item iadd", self, other)
        return Item(self.value + "+" + other.value)

class Container(object):
    def __getitem__(self, key):
        print("Container getitem", key)
        return Item(key)
    def __setitem__(self, key, value):
        print("Container setitem", key, value)
        return self
    def __additem__(self, key, value):
        print("Container additem would be nice", key, value)
        return self

这是SELECT:

>>> c = Container()
>>> _ = c['key']
Container getitem key

这是INSERT:

>>> c['key'] = Item('other')
Container setitem key Item other

如何实施UPDATE?不分解为SELECT和INSERT:

>>> c['key'] += Item('other')
Container getitem key
Item iadd Item key Item other
Container setitem key Item key+other

那么有没有一种方法可以实现增强分配而不是分解步骤?不将所有行为放在Item类中?

你可以将上面的代码剪切并粘贴到python解释器中,或者在这个Python小提琴上试试: http://pythonfiddle.com/add-item-for-sequence/

related question显示self[key] += value

的反编译

1 个答案:

答案 0 :(得分:3)

不,没有神奇的__additem__方法。

c[k] += v变成了魔术方法调用:c.__setitem__(c.__getitem__(k).__iadd__(v))

包含__setitem__调用,因为并非所有Python对象都支持就地添加。不可变对象(如intfloat)不会,因此__add__将被调用而不是__iadd__(而__add__ 必须返回一个新值。)

我认为你可以按照自己想要的方式使数据库工作的唯一方法是编写__getitem__,这样它就会返回一个特殊的"项代理"类型。代理最初不会做任何事情(它没有自己的行为)。但是,当在其上查找属性或方法(或调用__magic__方法)时,它将执行必要的数据库操作以使其工作。对于大多数方法和属性查找,它需要查询数据库以获取实际数据,然后返回适当的方法或值。如果它是一个已知的就地修改方法(如append__iadd__),它可以改为执行不同的数据库操作(如UPDATE而不是{{1} })。

编写这样的代理类型并不容易,但也不是很荒谬。如果你想要处理许多类型的对象,那么就会有很多角落要覆盖。根据数据库可以容纳的类型集的范围有多窄,可能会缩小您需要代理复制到几个的方法和属性列表(例如算术和比较运算符,也许SELECT如果您只需要支持数字类型,则__int__

另一方面,当您只使用较少的代码执行__float__SELECT时,您可能会发现不值得开发。