当前位置:  开发笔记 > 编程语言 > 正文

python中的weakref列表

如何解决《python中的weakref列表》经验,为你挑选了3个好方法。

我需要一个弱引用列表,它们会在项目死亡时删除它们.目前,我这样做的唯一方法是不断刷新列表(手动删除死引用).

我知道有一个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()

Brian.. 6

你可以自己实现它,类似于你的工作方式,但是在尝试访问项目之前使用一个调用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

[编辑]添加更完整的列表实现.



1> Brian..:

你可以自己实现它,类似于你的工作方式,但是在尝试访问项目之前使用一个调用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> rewritten..:

您可以使用来自同一个weakref模块的WeakSet(它实际上是在其他地方定义的,但它是在那里导入的).

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


它还有不保留其条目顺序的缺点.
WeakSet只能存储可哈希的对象.
@PeterGraham和TokenMacGuy:OP没有说明他的订购要求.因此,如果他只是想要一个[无序]包含微弱的东西,如果这些东西是可以清洗的,那么WeakSet的想法看起来是可行的.如果事物是​​他自己设计的对象,也许他可以满足他自己对象的可洗需求.

3> gregorySalva..:

因为我需要像你这样的弱列表,我已经制作了一个并在pypi上发布它.

现在你可以这样做:

pip install weakreflist

然后:

from weakreflist import WeakList

推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有