- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在构建一个子类 dict
并覆盖 __setitem__
的类。我想确定在所有可能设置字典项的情况下都会调用我的方法。
我发现了三种情况,Python(本例中为 2.6.4)在设置值时不调用我重写的 __setitem__
方法,而是直接调用 PyDict_SetItem
setdefault
方法中update
方法中作为一个非常简单的测试:
class MyDict(dict):
def __setitem__(self, key, value):
print "Here"
super(MyDict, self).__setitem__(key, str(value).upper())
>>> a = MyDict(abc=123)
>>> a['def'] = 234
Here
>>> a.update({'ghi': 345})
>>> a.setdefault('jkl', 456)
456
>>> print a
{'jkl': 456, 'abc': 123, 'ghi': 345, 'def': '234'}
您可以看到,仅在显式设置项目时才调用被覆盖的方法。为了让 Python 始终调用我的 __setitem__
方法,我不得不重新实现这三个方法,如下所示:
class MyUpdateDict(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __setitem__(self, key, value):
print "Here"
super(MyUpdateDict, self).__setitem__(key, value)
def update(self, *args, **kwargs):
if args:
if len(args) > 1:
raise TypeError("update expected at most 1 arguments, got %d" % len(args))
other = dict(args[0])
for key in other:
self[key] = other[key]
for key in kwargs:
self[key] = kwargs[key]
def setdefault(self, key, value=None):
if key not in self:
self[key] = value
return self[key]
为了知道 Python 将总是调用我的 __setitem__
方法,我是否需要重写任何其他方法?
更新
根据 gs 的建议,我尝试像这样子类化 UserDict(实际上是 IterableUserDict,因为我想遍历键):
from UserDict import *;
class MyUserDict(IterableUserDict):
def __init__(self, *args, **kwargs):
UserDict.__init__(self,*args,**kwargs)
def __setitem__(self, key, value):
print "Here"
UserDict.__setitem__(self,key, value)
此类似乎在 setdefault
上正确调用了我的 __setitem__
,但在 update
或初始数据为提供给构造函数。
更新 2
Peter Hansen 的建议让我更仔细地查看了 dictobject.c,我意识到 update 方法可以简化一点,因为内置的字典构造函数无论如何都只是调用内置的 update 方法。现在看起来像这样:
def update(self, *args, **kwargs):
if len(args) > 1:
raise TypeError("update expected at most 1 arguments, got %d" % len(args))
other = dict(*args, **kwargs)
for key in other:
self[key] = other[key]
最佳答案
我正在回答我自己的问题,因为我最终决定我真的确实想要继承 Dict,而不是创建一个新的映射类,并且 UserDict 在某些情况下仍然遵循底层的 Dict 对象情况,而不是使用提供的 __setitem__
。
在阅读和重新阅读 Python 2.6.4 源代码(主要是 Objects/dictobject.c
,但我在其他地方寻找各种方法的使用位置)之后,我的理解是以下代码 足以在每次更改对象时调用我的 __setitem__ ,否则其行为与 Python Dict 完全相同:
Peter Hansen 的建议让我更仔细地查看 dictobject.c
,我意识到我原来的答案中的更新方法可以简化一点,因为内置的字典构造函数只是调用无论如何,内置的更新方法。因此,我的答案中的第二个更新已添加到下面的代码中(由一些乐于助人的人;-)。
class MyUpdateDict(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __setitem__(self, key, value):
# optional processing here
super(MyUpdateDict, self).__setitem__(key, value)
def update(self, *args, **kwargs):
if args:
if len(args) > 1:
raise TypeError("update expected at most 1 arguments, "
"got %d" % len(args))
other = dict(args[0])
for key in other:
self[key] = other[key]
for key in kwargs:
self[key] = kwargs[key]
def setdefault(self, key, value=None):
if key not in self:
self[key] = value
return self[key]
我已经用这段代码测试过了:
def test_updates(dictish):
dictish['abc'] = 123
dictish.update({'def': 234})
dictish.update(red=1, blue=2)
dictish.update([('orange', 3), ('green',4)])
dictish.update({'hello': 'kitty'}, black='white')
dictish.update({'yellow': 5}, yellow=6)
dictish.setdefault('brown',7)
dictish.setdefault('pink')
try:
dictish.update({'gold': 8}, [('purple', 9)], silver=10)
except TypeError:
pass
else:
raise RunTimeException("Error did not occur as planned")
python_dict = dict([('b',2),('c',3)],a=1)
test_updates(python_dict)
my_dict = MyUpdateDict([('b',2),('c',3)],a=1)
test_updates(my_dict)
它通过了。我尝试过的所有其他实现在某些时候都失败了。我仍然会接受任何表明我错过了什么的答案,但除此之外,我会在几天后勾选这个旁边的复选标记,并将其称为正确答案:)
关于python - 子类化 Python 字典以覆盖 __setitem__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2060972/
我希望能够拦截函数内的变量赋值并执行自定义代码。我试过如下创建自定义字典: class userdict(dict): def __setitem__(self, key, value):
我正在尝试创建一个将数据存储在本地缓冲区中并充当数据库接口(interface)的类。我有以下代码: class Table(object): def __init__(self, ta
我在第 3 方模块中找到了这段代码,在这种情况下,该模块忽略了 foo[::step] 或 key.step。 def __getitem__(self, key): if isinstanc
我正在运行 Python 2.7.10。 我需要拦截列表中的更改。 “更改”是指任何在浅层意义上修改列表的内容(如果列表由相同顺序的相同对象组成,则列表不会更改,而不管这些对象的状态如何;否则,它是)
我有以下字典: class Only5Items(dict): def __setitem__(self, key, value): if len(self) < 5:
这是我所做的,尝试为类似 dict 的数据库创建一个包装器,以及其他功能: class database(object): def __init__(self, name):
我不想在使用 __setitem__ 时测试键的类型。但奇怪的是,我发现使用多个键时,部分代码被省略了。这是我的测试类: class foo(): def __init__(self):
我有一个 list 的子类这在列表的组件上添加了一些管理内容。一切正常,但 mypy投诉 super 的签名调用 __setitem__ . 这是问题减少到最低限度: from typing impo
在下面的示例中,如果通过 = 设置数据,则有一个具有 __setitem__ 方法的类可以正常工作。但是,如果例如 list 类型的数据是使用 .append 方法隐式设置的,则不会调用 __seti
在下面的示例中,如果通过 = 设置数据,则有一个具有 __setitem__ 方法的类可以正常工作。但是,如果例如 list 类型的数据是使用 .append 方法隐式设置的,则不会调用 __seti
如果你这样做 import gdbm db = gdbm.open('foo', 'cs') 你得到一个对象: 您现在可以通过以下方式在数据库中设置键和值: db['foo'] = 'bar' pr
我有以下类(class): class autoArray2(numpy.ndarray): def __new__(self, *args, **kwargs): obj =
我有以下代码: class VectorN(object): def __init__(self, param): if isinstance(param, int):
我正在构建一个子类 dict 并覆盖 __setitem__ 的类。我想确定在所有可能设置字典项的情况下都会调用我的方法。 我发现了三种情况,Python(本例中为 2.6.4)在设置值时不调用我重写
我试图实现一个(原型(prototype),而不是生产)版本的持久字典,它使用磁盘上的pickle作为持久存储。但是,pickle.load 出于自身目的调用 __setitem__ ,并且(当然)会
基于Paul's answer ,我尝试运行以下冒泡排序算法,该算法使用 slice 和 __setitem__ 方法;我确信有一些简单的事情我做得不对,不确定那可能是什么? 代码 def bubbl
在下面的语句中定义一个类的行为: my_object[item] = ... 我知道我需要定义 __setitem__ 方法。 下面的语句需要定义什么方法: my_object[item] += ..
谁能告诉我为什么这段代码提示容器上没有 __setitem__?我以为我只需要容器上的 __getitem__ 来获取项目,然后 __iadd__ 来设置值,不知道为什么它期待 __setitem__
我正在开发一个自定义类来使用 Python 处理矩阵。我遇到了一个问题,我的测试程序显然没有向我的 __setitem__ 方法传递足够的参数。这是代码: def __setitem__(self,
var obj = {} obj.__setitem__ = function(key, value){ this[key] = value * value } obj.x = 2 // 4 o
我是一名优秀的程序员,十分优秀!