Overriding iadd for dictionary like objects

Jan Kaliszewski zuo at chopin.edu.pl
Thu Aug 27 03:02:19 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.__setitem__('a', 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