如何改变Python字典的__setattr__行为?
在Python中,所有东西都有一个类。因此,dict
(字典)也有自己的类。
所以,从理论上讲,我应该能够改变字典中键值对赋值的行为。
举个例子:
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)
来查看。但是,dict
(字典)和 list
(列表)却不是这样。
我该如何通过重写 dict.__setattr__()
方法来实现我想要的行为呢?
4 个回答
2
你不能这样做。dict
类是用C语言写的,是Python自带的一个功能,这意味着你不应该对它进行任何修改。
不过,你可以从这个类继承,创建一个自己的子类,并且可以在这个子类中重写你想要的方法。
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
并重写所有的方法(可以参考 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
12
在这种情况下,必须重写的是 __setitem__
,这其实很简单:
class MyDict(dict):
def __setitem__(self, key, value):
dict.__setitem__(self, key, 2 * value)
举个例子:
>>> m = MyDict()
>>> m[0] = 5
>>> m
{0: 10}
__setattr__
控制的是对象的属性是如何被设置的(不是键值对)。