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.