Skip to content Skip to sidebar Skip to footer

Weakref List In Python

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 manual

Solution 1:

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

classWeakList(list):
    def__init__(self, seq=()):
        list.__init__(self)
        self._refs = []
        self._dirty=Falsefor x in seq: self.append(x)

    def_mark_dirty(self, wref):
        self._dirty = Truedefflush(self):
        self._refs = [x for x in self._refs if x() isnotNone]
        self._dirty=Falsedef__getitem__(self, idx):
        if self._dirty: self.flush()
        return self._refs[idx]()

    def__iter__(self):
        for ref in self._refs:
            obj = ref()
            if obj isnotNone: yield obj

    def__repr__(self):
        return"WeakList(%r)" % list(self)

    def__len__(self):
        if self._dirty: self.flush()
        returnlen(self._refs)

    def__setitem__(self, idx, obj):
        ifisinstance(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]

    defappend(self, obj):
        self._refs.append(weakref.ref(obj, self._mark_dirty))

    defcount(self, obj):
        returnlist(self).count(obj)

    defextend(self, items):
        for x in items: self.append(x)
        
    defindex(self, obj):
        returnlist(self).index(obj)
    
    definsert(self, idx, obj):
        self._refs.insert(idx, weakref.ref(obj, self._mark_dirty))
        
    defpop(self, idx):
        if self._dirty: self.flush()
        obj=self._refs[idx]()
        del self._refs[idx]
        return obj

    defremove(self, obj):
        if self._dirty: self.flush() # Ensure all valid.for i, x inenumerate(self):
            if x == obj:
                del self[i]
        
    defreverse(self):
        self._refs.reverse()

    defsort(self, cmp=None, key=None, reverse=False):
        if self._dirty: self.flush()
        if key isnotNone:
            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 inlist(self)

    def__mul__(self, n):
        return WeakList(list(self)*n)
        
    def__imul__(self, n):
        self._refs *= n
        return self

Solution 2:

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 importWeakList

Solution 3:

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()>>>classObj(object): pass# can't weakref simple objects>>>a = Obj()>>>s.add(a)>>>printlen(s)
1
>>>del a>>>printlen(s)
0

Solution 4:

Why can't you just do it like this:

import weakref

classWeakList(list):
    defappend(self, item):
        list.append(self, weakref.ref(item, self.remove))

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

Solution 5:

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

classWeakRefList(object):
    "weakref psuedo list"def__init__(yo):
        yo._items = list()
    def__iter__(yo):
        yo._items = [s for s in yo._items if s() isnotNone]
        return (s() for s in yo._items if s() isnotNone)
    def__len__(yo):
        yo._items = [s for s in yo._items if s() isnotNone]
        returnlen(yo._items)
    defappend(yo, new_item):
        yo._items.append(weakref.ref(new_item))
        yo._items = [s for s in yo._items if s() isnotNone]

Post a Comment for "Weakref List In Python"