In Python, everything has a class. Therefore dict
also has a class.
So, in theory, I should be able to change the implementation of the keyvalue assignment behavior.
Example:
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
I noticed that most objects have attributes listed in OBJECT.__dict__
or vars(OBJECT)
. But this isn’t the case for dict
or list
.
How can I get the desired behavior by overriding dict.__setattr__()
method?
It is __setitem__
that have to be overriden in this case -
and it is as simples as:
class MyDict(dict):
def __setitem__(self, key, value):
dict.__setitem__(self, key, 2 * value)
Example:
>>> m = MyDict()
>>> m[0] = 5
>>> m
{0: 10}
__setattr__
controls how object attributes themselves (not key/value pairs) are attributed.
Be careful when subclassing dict
. If you just override __setitem__
, then other dict
methods, such as update
, will not call your __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.
In order to create a dict-like object, you either need to subclass dict
and override all the methods (see OrderedDict for an example of this approach), or subclass collections.MutableMapping
and override a small subset those methods (from which all the other methods are derived).
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
You can’t. The dict
class is written in C a Python builtin, which means you can’t really shouldn’t do any kind of monkey-patching on it.
You can, however, inherit from it and override whatever methods you want in your subclass.
If you run the following code in the console you will see that the dict class/object is read-only:
{}.__setitem__ = None
AttributeError: 'dict' object attribute '__setitem__' is read-only
You need to what @jsbueno posted, which is create a subclass of the dict class, override the __setitem__
method, multiply the value by two and then call the original dict __setitem__
method.