4

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

应用程序是一种数据库。考虑__getitem__使用 SELECT 和__setitem__INSERT 来实现。__additem__UPDATE应该有类似的东西,对吧?

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

这是选择:

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

这是插入:

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

如何实现更新?在不分解为 SELECT 和 INSERT 的情况下:

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

那么有没有办法以不同于分解步骤的方式实现增强分配?没有将所有行为放在 Item 类中?


您可以将上述代码剪切并粘贴到 python 解释器中,或者在这个 Python fiddle 上尝试:http: //pythonfiddle.com/add-item-for-sequence/


一个相关的问题显示了反编译self[key] += value

4

1 回答 1

3

不,没有神奇的__additem__方法。

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

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

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

编写这样的代理类型不会很容易,但也不是很困难。如果您想处理多种类型的对象,将会有很多角落案例需要覆盖。根据您的数据库可以容纳的一组类型的范围,可能会将您需要代理复制的方法和属性列表缩小到少数几个(例如算术和比较运算符,也许__int__并且__float__如果您只需要支持数字类型)。

另一方面,当你可以用更少的代码做 aSELECT和 an时,你可能会发现开发工作不值得。INSERT

于 2016-04-02T09:32:53.400 回答