自动删除类实例,当其中一个属性死亡时 [英] Automatically delete class instance when one of its attributes becomes dead

查看:89
本文介绍了自动删除类实例,当其中一个属性死亡时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

设置



说我有一个 Snit

  class Snit():pass 

Snot ,其中包含最弱的引用,例如四个 Snit s:

  import weakref 
class Snot():
def __init __(self,s1 = None,s2 = None,s3 = None,s4 =没有)
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):
返回Snot(snits [w],snits [x],snits [y],snits [z])

列表 snit s(a snit_list 因为它是):

  snit_list = [] 
为我的范围(12):
snit_list .append(Snit())

现在我列出一个 Snot snit_list 中使用 Snit



<$ (3)中的i
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;死> 

这不能忍受!一个 Snot 与死亡 Snit 显然是完全无意义的。



所以我真的很喜欢任何引用 Snot 至少以一个或多个 Snit 已被销毁,无。但是,理想的情况是,从 snot_list 列表中也可以自动删除 Snot c $ c> len(snot_list)按照删除的数量缩小 Snot s)。



这是一个很好的方法吗?



澄清:



A Snot 是一个对象只有存在有效的一组 Snit s(有效表示它具有相同数量的定义的 Snit s被初始化),具有以下行为:


  1. 如果有任何一个 Snit Snot 中的$ c>(当没有强烈的引用仍然存在)时, Snot 也应该消失是为什么我将 s1 s2 等设置为弱引用)。请注意, Snot 可以已初始化为4,3,2或1 Snit Snit 的数量并不重要, Snit 死亡是什么事项。

  2. 如果包含对 Snit 的引用的任何一个 Snot Snit 仍然存在。

  3. 可选:当 Snot 被删除时,包含对 Snot 对象也被更新( Snot 获取 pop ped)

  4. 可选:当所有 c $ c>引用一个 Snit 之前, Snots Snit 也消失了,包含 Snit 的任何数据结构将按照#3( Snit 获取 pop ped)。

所以理想的解决方案将允许我设置好这样的代码,这样我可以编写这样的代码:

  snits = get_snits_list some_input_with_10000_snits)
snots = get_snots_list(some_cross_referenced_input_with_8000_snots)
#eg:输入文件将会说:
#snot数字12由snits 1,4,7
#snot number 45是由snits 8,7,0,14
do_stuff_with_snits()
snits.pop(7)#snit 7是snot 12和45共同的
assert len(snots) == 7998 #snots 12和45已被删除

但是,如果这太难了,不适用于:

  assert snots [12] ==无
assert snots [45] ==无

我有兴趣改变事情。例如,如果它使设计更容易,我认为删除对 Snit s的弱引用是很好的,或者将它们移动到 Snit s而不是 Snot 成员是弱引用(虽然我看不出这些更改如何改善事情)。



我还考虑创建 Snot 子类 - ClearSnot 其中1 Snit YellowSnot with 2 Snit s, code> GreenSnot 与 3 Snit`s等。我不确定这是否会使事情更容易维护或更难。

解决方案

没有什么是真正的自动。您需要具有手动运行的功能来检查死亡 Snit s,或者具有作为 Snot 只要有任何有趣的事情发生在 Snot 来检查并删除死亡 Snit



例如:

  class Snot:
...
def __repr __(self):
#检查并删除任何死的Snits
self._remove_dead_snits()
return ...
def _remove_dead_snits自我):
如果self.s1()为无:
self.s1 =无
...#等等等等

有趣的部分是将该调用添加到 _remove_dead_snits 中,以便每个有趣的交互与 Snot - 例如 __ getitem __ __ iter __ ,以及您可以做什么






实际上,再想一想,如果你在每个 Snot 可以使用四个可能的 Snit ,您可以使用 SnitRef 描述符 - 以下是代码,并对原件进行了一些更改:

  import weakref 

class Snit(object):
def __init __(self,value):
self.value = value#仅用于测试
def __repr __(self):
return'Snit (%r)'%self.value

class SnitRef(object):#对象在Python 3中不需要
def __get __(self,inst,cls = None):
如果inst是None:
return self
return self.ref()#none或obj
def __set __(self,inst,obj):
self.ref = weakref.ref(obj)


类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)
打印(snot.s2)
snits.pop(2)
打印snits
打印(snot.s2)

运行时:

  $($)
[Snit(0),Snit(1),Snit(3)]


Set Up

Say I have a Snit:

class Snit(): pass

And a Snot, which contains weak references to up to, say, four Snits:

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)

I also have a Snot factory:

def snot_factory(snits,w,x,y,z):
    return Snot(snits[w],snits[x],snits[y],snits[z])

And a list of Snits (a snit_list as it were):

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

Now I make a list of Snots using the Snits in my snit_list:

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

The Problem

Whoops! I don't need snit_list[3] anymore, so I'll go ahead and remove it:

snit_list.pop(3)

But now I have a Snot hanging out there with a dead Snit:

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

This cannot stand! A Snot with a dead Snit is - obviously - total nonsense.

So I would really like for any references to the Snot to at least return as None after one or more of its Snits has been destroyed. But ideally, it would be even better for the Snot to be automatically removed from the snot_list list as well (len(snot_list) shrinks by the number of removed Snots).

What's a good way of going about this?

Clarification:

A Snot is an object that should only exist when there is a valid set of Snits ("valid" means it has the same number of defined Snits it was initialized with), with the following behavior:

  1. If any one Snit in a Snot goes away (when no strong references remain), the Snot should also go away (this is why I have set the s1, s2, etc to be weak references). Note that a Snot could have been initialized with 4, 3, 2, or 1 Snit. The number of Snits doesn't matter, the death of the Snit is what matters.
  2. If any one Snot that contains a reference to a Snit goes away, the Snit remains.
  3. OPTIONAL: When a Snot is deleted, the data structure containing the reference to the Snot object is updated as well (the Snot gets popped)
  4. OPTIONAL: When ALL the Snots that reference a certain Snit are gone, the Snit goes away too, and any data structures containing the Snit are updated as in #3 (the Snit gets popped).

So the ideal solution will allow me to set things up such that I can write code like this:

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

However, if this is too hard, I'd be fine with:

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

I am open to changing things around somewhat. For example, if it makes the design easier, I think it would be fine to remove the weak references to the Snits, or to maybe move them instead to the list of Snits instead of having the Snot members be weak refs (though I don't see how either of these changes would improve things).

I have also considered creating Snot subclasses - ClearSnot with 1 Snit, YellowSnot with 2 Snits, GreenSnot with 3Snit`s, etc. I'm uncertain if this would make things easier to maintain, or more difficult.

解决方案

Nothing is truly automatic. You'll need to either have a function that you run manually to check for dead Snits, or have a function that is part of Snot that is called whenever anything interesting happens to a Snot to check for, and remove, dead Snits.

For example:

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

The fun part is adding that call to _remove_dead_snits for every interesting interaction with a Snot -- such as __getitem__, __iter__, and whatever else you may do with it.


Actually, thinking a bit more about this, if you only have the four possible Snits per each Snot you could use a SnitRef descriptor -- here's the code, with some changes to your original:

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)

and when run:

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

这篇关于自动删除类实例,当其中一个属性死亡时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆