pyplot - python matplotlib plot points
lista débil en python (6)
Necesito una lista de referencias débiles que borre elementos cuando mueren. Actualmente, la única forma que tengo de hacer esto es seguir limpiando la lista (eliminando las referencias muertas manualmente).
Soy consciente de que hay un WeakKeyDictionary y un WeakValueDictionary, pero realmente busco una WeakList, ¿hay alguna forma de hacerlo?
Aquí hay un ejemplo:
import weakref
class A(object):
def __init__(self):
pass
class B(object):
def __init__(self):
self._references = []
def addReference(self, obj):
self._references.append(weakref.ref(obj))
def flush(self):
toRemove = []
for ref in self._references:
if ref() is None:
toRemove.append(ref)
for item in toRemove:
self._references.remove(item)
b = B()
a1 = A()
b.addReference(a1)
a2 = A()
b.addReference(a2)
del a1
b.flush()
del a2
b.flush()
¿Cómo planeas usar B
? Lo único que hago con la lista debref que construí es iterar sobre ella, por lo que su implementación es 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]
¿Por qué no puedes hacerlo así?
import weakref
class WeakList(list):
def append(self, item):
list.append(self, weakref.ref(item, self.remove))
Y luego haga lo mismo para __iadd__
, extend
, etc. Trabaja para mí.
Como necesitaba una lista débil como tú, la hice y la publico en pypi.
ahora puedes hacer
pip install weakreflist
entonces:
from weakreflist import WeakList
Puede implementarlo usted mismo, de manera similar a como lo ha hecho, pero con una subclase de lista que llama a flush () antes de intentar acceder a un elemento.
Obviamente, no desea hacer esto en todos los accesos, pero puede optimizar esto estableciendo una devolución de llamada en la referencia débil para marcar la lista como sucia cuando algo muere. Entonces, solo necesita borrar la lista cuando algo haya muerto desde el último acceso.
Aquí hay una clase de lista implementada usando este método. (Tenga en cuenta que no se ha probado mucho, y que algunos métodos no se implementan de manera muy eficiente (por ejemplo, aquellos que simplemente se convierten en una lista real y llaman al método), pero debería ser un punto de partida razonable:
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
[Editar] Agregar una implementación de lista más completa.
Puede usar WeakSet desde el mismo módulo débil de referencia (en realidad está definido en otra parte, por cierto, pero se importa allí).
>>> 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
Utilice una función de devolución de llamada pasada al segundo argumento de un valor débil.
Este código debería funcionar:
import weakref
class weakRefList(list):
def addReference(self, obj):
self._references.append(weakref.proxy(obj, self.remove))