当类实例的某个属性失效时自动删除它

2024-09-30 10:36:24 发布

您现在位置:Python中文网/ 问答频道 /正文

设置

假设我有一个Snit

class Snit(): pass

以及一个Snot,它包含多达四个Snit的弱引用:

^{pr2}$

我还有一个Snot工厂:

^{3}$

以及Snitlist(原为asnit_list):

snit_list = []
for i in range(12):
    snit_list.append(Snit())

现在,我使用我的snit_list中的Snit列出Snot

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)

但现在我有一个Snot和一个死人在一起Snit

snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>

这不能忍受!一个死了的Snot显然是完全无稽之谈。在

所以我真的希望任何对Snot的引用,至少在它的一个或多个Snit被销毁后返回为None。但在理想情况下,最好将Snotsnot_list列表中自动删除(len(snot_list)会因删除的Snot个数而缩小)。在

这样做的好方法是什么?在

澄清:

Snot是一个仅当存在一组有效的Snits时才应存在的对象(“valid”表示它具有与初始化时相同数量的已定义的Snit),其行为如下:

  1. 如果Snot中的任何一个Snit消失了(当没有强引用保留时),Snot也应该消失(这就是为什么我将s1s2等设置为弱引用的原因)。请注意,Snot可能已经用4、3、2或1^{来初始化。Snit的数目无关紧要,^{的死亡才是重要的。在
  2. 如果任何一个Snot包含对Snit的引用消失,则{}仍然存在。在
  3. 可选:删除Snot时,包含对Snot对象的引用的数据结构也会更新(Snot得到{}ped)
  4. 可选:当所有引用某个SnitSnots都不存在时,Snit也会消失,任何包含{}的数据结构都会像3中那样更新(这个Snit得到{}ped)。在

因此,理想的解决方案将允许我设置一些东西,以便我可以编写如下代码:

snits = get_snits_list(some_input_with_10000_snits)
snots = get_snots_list(some_cross_referenced_input_with_8000_snots)
#e.g.: the input file will say:
#snot number 12 is made of snits 1, 4, 7
#snot number 45 is made of snits 8, 7, 0, 14
do_stuff_with_snits()
snits.pop(7) #snit 7 is common to snot 12 and 45
assert len(snots) == 7998 #snots 12 and 45 have been removed

但是,如果这太难了,我可以:

assert snots[12] == None
assert snots[45] == None

我愿意改变一些事情。例如,如果这使设计更容易,我认为最好删除对Snits的弱引用,或者将它们移到Snit的列表中,而不是让Snot成员成为弱引用(尽管我看不出这两个更改如何改进)。在

我还考虑过创建Snot子类-ClearSnot,用1SnitYellowSnot用2Snit,用3Snit创建{},等等。我不确定这是否会使事情更容易维护,还是更困难。在


Tags: innoneforinputiswithassertlist
2条回答

好的,你有一个Snot,变量是Snits

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消失时,它就等于None。在


我知道snits和{}都是list,顺序重要吗?如果顺序不重要,可以使用sets,这样就有可能有一个性能解决方案,其中死的{}实际上从数据结构中删除了,但这会增加复杂性:每个Snot必须跟踪它所在的数据结构,并且每个Snit必须保留一个列表,其中Snot它在里面,而魔法必须生活在{}中,这可能会导致其他问题。。。在

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

例如:

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

有趣的部分是添加对_remove_dead_snits的调用,以便与__getitem____iter___remove_dead_snits的每个有趣的交互,以及您可以对它做的任何其他操作。在


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

^{pr2}$

跑步时:

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

相关问题 更多 >

    热门问题