Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #109750 > unrolled thread

Re: UserList - which methods needs to be overriden?

Started byPeter Otten <__peter__@web.de>
First post2016-06-09 16:13 +0200
Last post2016-06-09 16:13 +0200
Articles 1 — 1 participant

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: UserList - which methods needs to be overriden? Peter Otten <__peter__@web.de> - 2016-06-09 16:13 +0200

#109750 — Re: UserList - which methods needs to be overriden?

FromPeter Otten <__peter__@web.de>
Date2016-06-09 16:13 +0200
SubjectRe: UserList - which methods needs to be overriden?
Message-ID<mailman.117.1465481634.2306.python-list@python.org>
Nagy László Zsolt wrote:

> 
>> Using the built-in list or dict is problematic because sometimes the
>> subclass methods are ignored when the internal data is accessed (sorry, I
>> don't have an example).
> Are you suggesting that I should use UserList and UserDict instead of
> list and dict? What is the truth? Was UserDict left in collections for
> backward compatibility, or not?
> 
>>
>> How detailed is your change notification? If it's always the same method
>> invocation you may be able to create wrappers like
>>
>> def whatever(self, *args):
>>     try:
>>         return super().whatever(*args)
>>     finally:
>>         self.changed()
>>
>> automatically, and the base class, be it list or UserList or whatever
>> becomes a detail that can be chosen on a case by case basis.
> My actual solution looks like this:
> 
> 
> class ObservableCollection(Observable):
>     @contextmanager
>     def notify(self):
>         self.notify_observers(EVT_BEFORE_COLLECTION_CHANGED)
>         yield
>         self.notify_observers(EVT_AFTER_COLLECTION_CHANGED)
> 
> class ObservableList(ObservableCollection, list):
>     __slots__ = []
> 
>     def remove(self, value):
>         with self.notify(): super().remove(value)
> 
>     def clear(self):
>         with self.notify(): super().clear()
> 
>     def pop(self):
>         with self.notify(): return super().pop()
> 
> It seems to be working with the built in list, dict and set types.
> 
> There must be a better way! Something like this:
> 
> @wrap_notify('remove', 'clear', 'append', 'insert', 'sort'):
> class ObservableList(ObservableCollection, list):
>     pass
> 
> I just can't find out the right syntax.

[Looks like you made progress while I struggled to come up with the 
following. I'll post it anyway.]

$ cat observable_list.py
from contextlib import contextmanager

EVT_BEFORE_COLLECTION_CHANGED = "EVT_BEFORE_COLLECTION_CHANGED"
EVT_AFTER_COLLECTION_CHANGED = "EVT_AFTER_COLLECTION_CHANGED"

class Observable:
    def notify_observers(self, message):
        print(message)


def wrap_notify(*names):
    def wrap_methods(cls):
        for name in names:
            method = wrap_method(getattr(cls, name), name)
            setattr(cls, name, method)
        return cls
    return wrap_methods


def wrap_method(method, name):
    def wrapped_method(self, *args, **kw):
        with self.notify():
            return method(self, *args, **kw)
    return wrapped_method


class ObservableCollection(Observable):
    @contextmanager
    def notify(self):
        self.notify_observers(EVT_BEFORE_COLLECTION_CHANGED)
        yield
        self.notify_observers(EVT_AFTER_COLLECTION_CHANGED)


@wrap_notify('remove', 'clear', 'append', 'insert', 'sort')
class ObservableList(ObservableCollection, list):
    pass

items = ObservableList()
items.append(42)
items.append(41)
items.sort()
print(items)
$ python3 observable_list.py 
EVT_BEFORE_COLLECTION_CHANGED
EVT_AFTER_COLLECTION_CHANGED
EVT_BEFORE_COLLECTION_CHANGED
EVT_AFTER_COLLECTION_CHANGED
EVT_BEFORE_COLLECTION_CHANGED
EVT_AFTER_COLLECTION_CHANGED
[41, 42]

[toc] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web