`self[key] += value` 的魔法方法?
Magic method for `self[key] += value`?
有一个 Python 魔术方法 __setitem__
用于分配 =
序列类型。 在容器级别是否有增强赋值的神奇方法+=
?该操作似乎确实优雅地分解为项目类型的增强赋值。这是合乎逻辑的。但是几乎所有其他东西都有一个神奇的方法,我认为应该有一组用于序列类型上的这些运算符的方法。我错过了吗?
该应用程序是一种数据库。考虑使用 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
这是插入内容:
>>> 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 class?
中
您可以将上面的代码剪切并粘贴到 python 解释器中,或者在此 Python fiddle 上尝试:
http://pythonfiddle.com/add-item-for-sequence/
一个related question表示反编译self[key] += value
不,没有神奇的__additem__
方法。
c[k] += v
变成魔术方法调用:c.__setitem__(c.__getitem__(k).__iadd__(v))
.
包含 __setitem__
调用是因为并非所有 Python 对象都支持就地添加。不可变对象(如 int
和 float
)不会,因此 __add__
将被调用而不是 __iadd__
(并且 __add__
必须 return 一个新值)。
我认为使数据库按您希望的方式工作的唯一方法是编写 __getitem__
,使其 return 成为一种特殊的 "item proxy" 类型。代理最初什么都不做(它没有自己的行为)。但是,当在其上查找属性或方法(或调用 __magic__
方法)时,它会执行必要的数据库操作以使其工作。对于大多数方法和属性查找,它需要查询数据库以获取实际数据,然后 return 适当的方法或值。如果调用的是已知的就地修改方法(如 append
或 __iadd__
,它可以改为执行不同的数据库操作(如 UPDATE
而不是 SELECT
).
编写这样的代理类型不会很容易,但也不难到离谱。如果你想处理多种类型的对象,就会有很多极端情况需要解决。根据您的数据库可以容纳的类型集有多窄,可能可以将您需要代理复制的方法和属性列表缩小到少数几个(例如算术和比较运算符,也许 __int__
和 __float__
如果你只需要支持数字类型)。
另一方面,您可能会发现,当您可以用更少的代码完成 SELECT
和 INSERT
时,不值得付出开发努力。
有一个 Python 魔术方法 __setitem__
用于分配 =
序列类型。 在容器级别是否有增强赋值的神奇方法+=
?该操作似乎确实优雅地分解为项目类型的增强赋值。这是合乎逻辑的。但是几乎所有其他东西都有一个神奇的方法,我认为应该有一组用于序列类型上的这些运算符的方法。我错过了吗?
该应用程序是一种数据库。考虑使用 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
这是插入内容:
>>> 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 class?
中您可以将上面的代码剪切并粘贴到 python 解释器中,或者在此 Python fiddle 上尝试: http://pythonfiddle.com/add-item-for-sequence/
一个related question表示反编译self[key] += value
不,没有神奇的__additem__
方法。
c[k] += v
变成魔术方法调用:c.__setitem__(c.__getitem__(k).__iadd__(v))
.
包含 __setitem__
调用是因为并非所有 Python 对象都支持就地添加。不可变对象(如 int
和 float
)不会,因此 __add__
将被调用而不是 __iadd__
(并且 __add__
必须 return 一个新值)。
我认为使数据库按您希望的方式工作的唯一方法是编写 __getitem__
,使其 return 成为一种特殊的 "item proxy" 类型。代理最初什么都不做(它没有自己的行为)。但是,当在其上查找属性或方法(或调用 __magic__
方法)时,它会执行必要的数据库操作以使其工作。对于大多数方法和属性查找,它需要查询数据库以获取实际数据,然后 return 适当的方法或值。如果调用的是已知的就地修改方法(如 append
或 __iadd__
,它可以改为执行不同的数据库操作(如 UPDATE
而不是 SELECT
).
编写这样的代理类型不会很容易,但也不难到离谱。如果你想处理多种类型的对象,就会有很多极端情况需要解决。根据您的数据库可以容纳的类型集有多窄,可能可以将您需要代理复制的方法和属性列表缩小到少数几个(例如算术和比较运算符,也许 __int__
和 __float__
如果你只需要支持数字类型)。
另一方面,您可能会发现,当您可以用更少的代码完成 SELECT
和 INSERT
时,不值得付出开发努力。