Подтвердить что ты не робот

Список слайдов в python

Мне нужен список слабых ссылок, который удаляет элементы, когда они умирают. В настоящее время единственный способ сделать это - сохранить очистку списка (удаление мертвых ссылок вручную).

Я знаю, что есть WeakKeyDictionary и WeakValueDictionary, но я действительно после WeakList, есть ли способ сделать это?

Вот пример:

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()
4b9b3361

Ответ 1

Вы можете реализовать его самостоятельно, подобно тому, как вы это сделали, но с подклассом списка, который вызывает flush(), прежде чем пытаться получить доступ к элементу.

Очевидно, вы не хотите делать это при каждом доступе, но вы можете оптимизировать это, установив обратный вызов на слабую ссылку, чтобы пометить список грязным, когда что-то умрет. Затем вам нужно только сбросить список, когда что-то скончалось с момента последнего доступа.

Здесь класс списка, реализованный с использованием этого метода. (Обратите внимание, что он не тестировался много, и некоторые методы не реализованы очень эффективно (например, те, которые просто конвертируются в реальный список и вызывают метод на нем), но это должна быть разумная отправная точка:

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

[Изменить] Добавить более полную реализацию списка.

Ответ 2

Вы можете использовать WeakSet из того же самого модуля weakref (он определенно определен в другом месте, а там импортирован).

>>> 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

Ответ 3

Поскольку мне нужен был список weakref, подобный вам, я сделал один и опубликовал его на pypi.

теперь вы можете сделать:

pip install weakreflist

то

from weakreflist import WeakList

Ответ 4

Использовать функцию обратного вызова, переданную второму аргументу функции weakref.

Этот код должен функционировать:

import weakref

class weakRefList(list):

    def addReference(self, obj):
        self._references.append(weakref.proxy(obj, self.remove))

Ответ 5

Почему вы не можете просто так:

import weakref

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

И затем выполните аналогичные для __iadd__, extend и т.д. Работает для меня.

Ответ 6

Как вы планируете использовать B? Единственное, что я когда-либо делал со списком weakref, который я построил, это перебрать его, поэтому его реализация проста:

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]