weakref list in python

后端 未结 6 1322
感情败类
感情败类 2021-02-04 05:08

I\'m in need of a list of weak references that deletes items when they die. Currently the only way I have of doing this is to keep flushing the list (removing dead references ma

相关标签:
6条回答
  • 2021-02-04 05:10

    Why can't you just do it like this:

    import weakref
    
    class WeakList(list):
        def append(self, item):
            list.append(self, weakref.ref(item, self.remove))
    

    And then do similar for __iadd__, extend etc. Works for me.

    0 讨论(0)
  • 2021-02-04 05:11

    You can use WeakSet from the very same weakref module (it's actually defined elsewhere by the way, but it's imported there).

    >>> from weakref import WeakSet
    >>> s = WeakSet()
    >>> class Obj(object): pass # can't weakref simple objects
    >>> a = Obj()
    >>> s.add(a)
    >>> print len(s)
    1
    >>> del a
    >>> print len(s)
    0
    
    0 讨论(0)
  • 2021-02-04 05:23

    As I needed a weakref list like you, I've made one and publish it on pypi.

    now you can do:

    pip install weakreflist
    

    then:

    from weakreflist import WeakList
    
    0 讨论(0)
  • 2021-02-04 05:29

    You could implement it yourself, similarly to how you have done, but with a list subclass that calls flush() before attempting to access an item.

    Obviously you don't want to do this on every access, but you can optimize this by setting a callback on the weak reference to mark the list dirty when something dies. Then you only need to flush the list when something has died since the last access.

    Here's a list class implemented using this method. (Note that it's not tested much, and some methods aren't implemented very efficiently (eg. those which just convert to a real list and call the method on that), but it should be a reasonable starting point:

    import weakref
    
    class WeakList(list):
        def __init__(self, seq=()):
            list.__init__(self)
            self._refs = []
            self._dirty=False
            for x in seq: self.append(x)
    
        def _mark_dirty(self, wref):
            self._dirty = True
    
        def flush(self):
            self._refs = [x for x in self._refs if x() is not None]
            self._dirty=False
    
        def __getitem__(self, idx):
            if self._dirty: self.flush()
            return self._refs[idx]()
    
        def __iter__(self):
            for ref in self._refs:
                obj = ref()
                if obj is not None: yield obj
    
        def __repr__(self):
            return "WeakList(%r)" % list(self)
    
        def __len__(self):
            if self._dirty: self.flush()
            return len(self._refs)
    
        def __setitem__(self, idx, obj):
            if isinstance(idx, slice):
                self._refs[idx] = [weakref.ref(obj, self._mark_dirty) for x in obj]
            else:
                self._refs[idx] = weakref.ref(obj, self._mark_dirty)
    
        def __delitem__(self, idx):
            del self._refs[idx]
    
        def append(self, obj):
            self._refs.append(weakref.ref(obj, self._mark_dirty))
    
        def count(self, obj):
            return list(self).count(obj)
    
        def extend(self, items):
            for x in items: self.append(x)
    
        def index(self, obj):
            return list(self).index(obj)
    
        def insert(self, idx, obj):
            self._refs.insert(idx, weakref.ref(obj, self._mark_dirty))
    
        def pop(self, idx):
            if self._dirty: self.flush()
            obj=self._refs[idx]()
            del self._refs[idx]
            return obj
    
        def remove(self, obj):
            if self._dirty: self.flush() # Ensure all valid.
            for i, x in enumerate(self):
                if x == obj:
                    del self[i]
    
        def reverse(self):
            self._refs.reverse()
    
        def sort(self, cmp=None, key=None, reverse=False):
            if self._dirty: self.flush()
            if key is not None:
                key = lambda x,key=key: key(x())
            else:
                key = apply
            self._refs.sort(cmp=cmp, key=key, reverse=reverse)
    
        def __add__(self, other):
            l = WeakList(self)
            l.extend(other)
            return l
    
        def __iadd__(self, other):
            self.extend(other)
            return self
    
        def __contains__(self, obj):
            return obj in list(self)
    
        def __mul__(self, n):
            return WeakList(list(self)*n)
    
        def __imul__(self, n):
            self._refs *= n
            return self
    

    [Edit] Add a more complete list implementation.

    0 讨论(0)
  • 2021-02-04 05:30

    How do you plan on using B? The only thing I ever do with the weakref list I built is iterate over it, so its implementation is simple:

    import weakref
    
    class WeakRefList(object):
        "weakref psuedo list"
        def __init__(yo):
            yo._items = list()
        def __iter__(yo):
            yo._items = [s for s in yo._items if s() is not None]
            return (s() for s in yo._items if s() is not None)
        def __len__(yo):
            yo._items = [s for s in yo._items if s() is not None]
            return len(yo._items)
        def append(yo, new_item):
            yo._items.append(weakref.ref(new_item))
            yo._items = [s for s in yo._items if s() is not None]
    
    0 讨论(0)
  • 2021-02-04 05:30

    Use a callback function passed to second argument of a weakref.

    This code should function:

    import weakref
    
    class weakRefList(list):
    
        def addReference(self, obj):
            self._references.append(weakref.proxy(obj, self.remove))
    
    0 讨论(0)
提交回复
热议问题