Overriding iadd for dictionary like objects

Jan Kaliszewski zuo at chopin.edu.pl
Thu Aug 27 03:00:10 CEST 2009


27-08-2009 o 00:48:33 Robert Kern <robert.kern at gmail.com> wrote:

> On 2009-08-26 17:16 PM, RunThePun wrote:
>> I'd like to build a database wrapper using DictMixin and allow items
>> to be appended by my own code. The problem is += is always understood
>> as setitem and getitem plainly.
>>
>> d = MyDict()
>> d['a'] = 1
>>
>> # this is the problem code that's I'd like to override. It's always
>> setitem('a', getitem('a') + 3)
>> d['a'] += 3
>> # i wanted to do something like my own 'appenditem' function which for
>> example could be useful if getitem is an expensive operation which can
>> be avoided.
>>
>> I hope that was clear enough of a request, it's really late at night
>> here...
>
> I'm sorry, this is just part of the syntax of Python. You cannot  
> override it.

Though
     d['a'] = 3
is equivalent to:
     d.__setitem__('a', 3)

The
     d['a'] += 3
*is not* equivalent to:
     d.__setitem__('a', d.__getitem__('a') + 3)
*but is* equivalent to:
     d.__getitem__('a').__iadd__(3)

Then you can override __getitem__() of MyDict in such a way that it
returns prepared (wrapped) object with overriden __iadd__() as you
want to.

How could I now it:

   1 import collections
   2 import functools
   3 import itertools
   4
   5
   6 def verbose_func(func):
   7     'Function decorator that makes a function "verbose"'
   8
   9     @functools.wraps(func, assigned=('__name__', '__doc__'))
  10     def func_wrapper(*args, **kwargs):
  11         iargs = (map(str, args))
  12         ikwargs = ('{0}={1}'.format(key, value)
  13                    for key, value in kwargs.items())
  14         func_args = ', '.join(itertools.chain(iargs, ikwargs))
  15         print('{0}({1})'.format(func.__name__, func_args))
  16         return func(*args, **kwargs)
  17
  18     return func_wrapper
  19
  20
  21 def verbose_cls(base):
  22     'Class decorator that makes callable attributes "verbose"'
  23
  24     quiet = ('__new__', '__repr__', '__str__')
  25
  26     def cls_wrapper(cls):
  27         for name in vars(base):
  28             attr = getattr(cls, name)
  29             if isinstance(attr, collections.Callable) and name not in  
quiet:
  30                 setattr(cls, name, verbose_func(attr))
  31         return cls
  32
  33     return cls_wrapper
  34
  35
  36 @verbose_cls(dict)
  37 class VerboseDict(dict):
  38     pass
  39
  40
  41 @verbose_cls(int)
  42 class MyInt(int):
  43
  44     @verbose_func
  45     def __iadd__(self, other):
  46         int.__add__(self, other)  # can do something more interesting
  47
  48
  49 if __name__ == '__main__':
  50     d = VerboseDict()
  51
  52     print("d['a'] = 3")
  53     d['a'] = MyInt(3)
  54
  55     print("d['a'] += 3")
  56     d['a'] += MyInt(3)

*j

-- 
Jan Kaliszewski (zuo) <zuo at chopin.edu.pl>



More information about the Python-list mailing list