如何改变python字典的__setattr__的行为?

时间:2012-01-06 01:46:20

标签: python types dictionary customization internals

在Python中,一切都有一个类。因此dict也有一个类。

因此,理论上,我应该能够改变keyvalue赋值行为的实现。


示例:

d = dict()
d['first'] = 3    # Internally d['first'] is stored as 6 [i.e. value*2 if value is INT]

print d['first']  # should print 6

d['second'] = 4 

print d['second'] # should print 8


我注意到大多数对象都有OBJECT.__dict__vars(OBJECT)中列出的属性。但dictlist并非如此。

如何通过覆盖dict.__setattr__()方法获得所需的行为?

4 个答案:

答案 0 :(得分:11)

在这种情况下必须覆盖__setitem__ - 它就像:

一样简单
class MyDict(dict):
    def __setitem__(self, key, value):
         dict.__setitem__(self, key, 2 * value)

示例:

>>> m  = MyDict()
>>> m[0] = 5
>>> m
{0: 10}

__setattr__控制对象属性本身(不是键/值对)的归属方式。

答案 1 :(得分:8)

子类化dict时要小心。如果您只是覆盖__setitem__,则其他dict方法(例如update)将不会调用您的__setitem__

class MyDict(dict):
    def __setitem__(self, key, value):
         dict.__setitem__(self, key, 2 * value)

d = MyDict()
d['first'] = 3
print(d['first'])
# 6

d.update({'first':4})
print(d['first'])
# 4                       # <--- __setitem__ was not called.

为了创建类似dict的对象,您需要子类dict并覆盖所有方法(请参阅OrderedDict以获取此方法的示例)或子类collections.MutableMapping并覆盖那些方法的小子集(从中派生所有其他方法)。

import collections

class MyDict2(collections.MutableMapping,dict):
    def __getitem__(self, key):
        return dict.__getitem__(self, key)
    def __setitem__(self, key, value):
         dict.__setitem__(self, key, 2 * value)
    def __delitem__(self, key):
        dict.__delitem__(self, key)
    def __iter__(self):
        return dict.__iter__(self)
    def __len__(self):
        return dict.__len__(self)
    def __contains__(self, x):
        return dict.__contains__(self, x)

d = MyDict2()
d['first'] = 3
print(d['first'])
# 6
d.update({'first':4})
print(d['first'])
# 8

答案 2 :(得分:2)

你做不到。 dict类是用C 编写的一个Python内置函数,这意味着你不能真的不应该对它进行任何类型的猴子修补。

但是,您可以从中继承并覆盖子类中所需的任何方法。

答案 3 :(得分:1)

如果在控制台中运行以下代码,您将看到dict类/对象是只读的:

{}.__setitem__ = None
AttributeError: 'dict' object attribute '__setitem__' is read-only

你需要@jsbueno发布的内容,即创建dict类的子类,覆盖__setitem__方法,将值乘以2,然后调用原始的dict __setitem__方法。