自动删除类实例,当其中一个属性死亡时 [英] Automatically delete class instance when one of its attributes becomes dead
问题描述
设置
说我有一个 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被初始化),具有以下行为:
- 如果有任何一个
Snit
Snot 中的$ c>(当没有强烈的引用仍然存在)时,Snot
也应该消失是为什么我将s1
,s2
等设置为弱引用)。请注意,Snot
可以已初始化为4,3,2或1Snit
。Snit
的数量并不重要,Snit
的死亡是什么事项。 - 如果包含对
Snit
的引用的任何一个Snot
,Snit
仍然存在。 - 可选:当
Snot
被删除时,包含对Snot
对象也被更新(Snot
获取pop
ped) - 可选:当所有 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 Snit
s:
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 Snit
s (a snit_list
as it were):
snit_list = []
for i in range(12):
snit_list.append(Snit())
Now I make a list of Snot
s using the Snit
s 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 Snit
s 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 Snot
s).
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 Snit
s ("valid" means it has the same number of defined Snit
s it was initialized with), with the following behavior:
- If any one
Snit
in aSnot
goes away (when no strong references remain), theSnot
should also go away (this is why I have set thes1
,s2
, etc to be weak references). Note that aSnot
could have been initialized with 4, 3, 2, or 1Snit
. The number ofSnit
s doesn't matter, the death of theSnit
is what matters. - If any one
Snot
that contains a reference to aSnit
goes away, theSnit
remains. - OPTIONAL: When a
Snot
is deleted, the data structure containing the reference to theSnot
object is updated as well (theSnot
getspop
ped) - OPTIONAL: When ALL the
Snots
that reference a certainSnit
are gone, theSnit
goes away too, and any data structures containing theSnit
are updated as in #3 (theSnit
getspop
ped).
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 Snit
s, or to maybe move them instead to the list of Snit
s 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 Snit
s, GreenSnot
with 3
Snit`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 Snit
s, 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 Snit
s.
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 Snit
s 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屋!