Python 当类实例的某个属性失效时自动删除该类实例 设置

Python 当类实例的某个属性失效时自动删除该类实例 设置,python,Python,假设我有一个Snit: class Snit(): pass snot_list[0].s4 # <weakref at 0x00BlahBlah; dead> 和一个Snot,其中包含对多达四个Snit的弱引用: import weakref class Snot(): def __init__(self,s1=None,s2=None,s3=None,s4=None): self.s1 = weakref.ref(s1) self.s2

假设我有一个
Snit

class Snit(): pass
snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>
和一个
Snot
,其中包含对多达四个
Snit
的弱引用:

import weakref
class Snot():
    def __init__(self,s1=None,s2=None,s3=None,s4=None):
        self.s1 = weakref.ref(s1)
        self.s2 = weakref.ref(s2)
        self.s3 = weakref.ref(s3)
        self.s4 = weakref.ref(s4)
我还有一个
Snot
工厂:

def snot_factory(snits,w,x,y,z):
    return Snot(snits[w],snits[x],snits[y],snits[z])
和一个
Snit
s的
list
(一个
Snit\u list
):

现在,我使用我的
Snit\u列表中的
Snit
s创建了一个
Snot
s列表:

snot_list = []
for i in range(3):
    snot_list.append(snot_factory(snit_list[4*i],snit_list[4*i+1],snit_list[4*i+2],snit_list[4*i+3]))
问题 哎呀!我不再需要
snit_list[3]
,所以我将继续删除它:

snit_list.pop(3)
但是现在我有一个鼻涕和一个死鼻涕挂在那里:

class Snit(): pass
snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>
但是,如果这太难,我可以:

assert snots[12] == None
assert snots[45] == None
我愿意改变一些事情。例如,如果它使设计更容易,我认为可以删除对
Snit
s的弱引用,或者将它们移动到
Snit
s的列表中,而不是让
Snot
成员成为弱引用(尽管我看不出这两个更改如何改善情况)


我还考虑过用1
Snit
创建
Snot
子类-
clearnot
,用2
Snit
创建
YellowSnot
,用3
Snit
创建
GreenSnot
子类,等等。我不确定这是否会使维护更容易,或者更困难

没有什么是真正自动的。您需要手动运行一个函数来检查死掉的
Snit
s,或者需要一个属于
Snot
的函数,该函数在
Snot
发生任何有趣的事情时调用,以检查并移除死掉的
Snit
s

class Snot(object):

    def __init__(self, *snits):
        self.snits = [weakref.ref(s) for s in snits]

    def __eq__(self, other):
        if not isinstance(other, self.__class__) and other is not None:
            return NotImplemented
        # are all my snits still valid
        valid = all(s() for s in self.snits)
        if other is None:
            return not valid  # if valid is True, we are not equal to None
        else:
            # whatever it takes to see if this snot is the same as the other snot
例如:

class Snot:
    ...
    def __repr__(self):
        # check for and remove any dead Snits
        self._remove_dead_snits()
        return ...
    def _remove_dead_snits(self):
        if self.s1() is None:
             self.s1 = None
        ... # and so on and so forth
有趣的部分是添加对
\u remove\u dead\u snits
的调用,用于与
Snot
进行每一次有趣的交互,例如
\u getitem\uuuuuuuuu
\uuuuu iter\uuuuuuuuuu
,以及您可以对其执行的任何其他操作


实际上,再仔细想想,如果每个
Snot
只有四个可能的
Snit
s,那么可以使用
SnitRef
描述符——下面是代码,对原始代码做了一些更改:

import weakref

class Snit(object):
    def __init__(self, value):
        self.value = value  # just for testing
    def __repr__(self):
        return 'Snit(%r)' % self.value

class SnitRef(object):   # 'object' not needed in Python 3
    def __get__(self, inst, cls=None):
        if inst is None:
            return self
        return self.ref()  # either None or the obj
    def __set__(self, inst, obj):
        self.ref = weakref.ref(obj)


class Snot(object):
    s0 = SnitRef()
    s1 = SnitRef()
    s2 = SnitRef()
    s3 = SnitRef()
    def __init__(self,s0=None,s1=None,s2=None,s3=None):
        self.s0 = s0
        self.s1 = s1
        self.s2 = s2
        self.s3 = s3

snits = [Snit(0), Snit(1), Snit(2), Snit(3)]
print snits
snot = Snot(*snits)
print(snot.s2)
snits.pop(2)
print snits
print(snot.s2)
运行时:

[Snit(0), Snit(1), Snit(2), Snit(3)]
Snit(2)
[Snit(0), Snit(1), Snit(3)]
None

好的,你有一个
Snot
,有一个可变的
Snit
s

class Snot(object):

    def __init__(self, *snits):
        self.snits = [weakref.ref(s) for s in snits]

    def __eq__(self, other):
        if not isinstance(other, self.__class__) and other is not None:
            return NotImplemented
        # are all my snits still valid
        valid = all(s() for s in self.snits)
        if other is None:
            return not valid  # if valid is True, we are not equal to None
        else:
            # whatever it takes to see if this snot is the same as the other snot
实际上,让类实例消失需要做更多的工作(比如让类上的
dict
来跟踪它们,然后其他数据结构只会使用弱引用——但这可能会很快变得难看),因此,下一个最好的方法是当它的任何
Snit
s消失时,使其变为等于
None



我看到
snit
snot
都是
list
s——顺序重要吗?如果顺序不重要,您可以使用
set
s来代替,这样就可以有一个性能解决方案,其中死的
snot
实际上从数据结构中删除,但这会增加复杂性:每个
snot
都必须跟踪它所处的数据结构,每一个Snit都必须保留一个列表,上面列出了它所在的Snot,而魔法必须存在于Snot中,这可能会导致其他问题……

如果有人想知道这个问题是否仅仅是使用Snot工厂的一个策略,答案可能是肯定的。简言之,Snit不是您能否澄清一下,您是否希望访问已删除的属性Snit
snots[0]。s4
返回None,Snot本身在缺少成员时返回None,或者其他什么?您的澄清令人困惑。)根据你的例子,鼻涕12有三个鼻涕,但是当你删除其中一个鼻涕时,整个鼻涕就失效了?对不起,是的。我将更好地澄清并删除此评论,但是,是的,一旦创建它的
Snit
中的任何一个被删除后,
Snit
就不应该再存在了(尽管它可以更改为列表中的另一个
Snit
)。我曾想过做一些与您上一段描述的类似的事情,但没有考虑使用集合。顺序并不一定重要,但如果没有某种顺序,我不知道在构建
Snot
时如何引用每个特定的
Snit
(而不仅仅是引用
Snit\u列表中的索引)。我得再考虑一下。@RickTeachey:这一点很好,
snits
必须保持一个
列表,但是如果
snots
可以成为一个
set
…我想我可以生活在一个
Snot
集合中。现在来了解如何跟踪对象实例中的
Snot
引用。这里是我唯一想到的一个想法:参考这里的另一个问题:
Snot
实际上只是一个专门的
Snit
容器。也许我应该编写一个通用容器(如您描述的performant解决方案),并将其子类化为
Snot
SnitList
SnotList
Snot
保存
Snit
s,
SnitList
也保存
Snit
s,
SnotList
(或
set
,无论什么)保存
Snot
s。