说我有Snit
:
class Snit(): pass
还有Snot
,其中包含对最多四个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)
我还有一个Snot
工厂:
def snot_factory(snits,w,x,y,z):
return Snot(snits[w],snits[x],snits[y],snits[z])
list
Snit
个snit_list
原样:
snit_list = []
for i in range(12):
snit_list.append(Snit())
现在,我使用Snot
中的Snit
制作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]))
糟糕!我不再需要snit_list[3]
了,所以我会继续删除它:
snit_list.pop(3)
但是现在我有一个Snot
在那里挂着Snit
:
snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>
这不能忍受! Snot
Snit
Snot
显然是完全无意义的。
所以我真的希望None
的任何引用在其Snit
的一个或多个被销毁之后至少返回为Snot
。但理想情况下,snot_list
自动从len(snot_list)
列表中删除也会更好(Snot
会因删除的Snot
数量而缩小。< / p>
有什么好办法解决这个问题?
Snit
是一个对象,只有当有一组有效的Snit
时才存在(“有效”表示它具有相同数量的已定义Snit
s被初始化with),具有以下行为:
Snot
中的任何一个Snot
消失(当没有强引用时),s1
也应该消失(这就是我设置s2
的原因},Snot
等是弱引用)。请注意,Snit
可以使用4,3,2或1 Snit
初始化。 Snit
的数量无关紧要,Snot
的死亡才是最重要的。 Snit
的引用的任何一个Snit
消失,则Snot
仍然存在。 Snot
时,包含对Snot
对象的引用的数据结构也会更新(pop
获取Snots
ped)Snit
的{{1}}消失时,Snit
也会消失,任何包含{{{}的数据结构都会消失1}}在#3中更新(Snit
得到Snit
ped)。所以理想的解决方案将允许我进行设置,以便我可以编写如下代码:
pop
然而,如果这太难了,我会好的:
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
的弱引用,或者可能将它们移动到Snit
的列表而不是Snit
成员是弱参考(虽然我不知道这些改变中的任何一个会如何改善)。
我还考虑创建Snot
子类 - Snot
,其中包含1 ClearSnot
,Snit
包含2 YellowSnot
s,Snit
包含3 { {1}}等等我不确定这是否会使事情更容易维护,或者更难。
答案 0 :(得分:2)
没有什么是真正的自动化。您需要拥有一个手动运行的函数来检查死Snit
,或者有一个函数是Snot
的一部分,只要Snot
发生任何有趣的事情就会被调用Snit
1}}检查并删除死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
s。
例如:
_remove_dead_snits
有趣的部分是将Snot
的调用添加到与__getitem__
的每次有趣互动中 - 例如__iter__
,Snit
,以及您可以使用的任何其他内容它
实际上,想一想这一点,如果每个Snot
只有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
描述符 - 这里是代码,对原始内容进行了一些更改:
{{1}}
并且在运行时:
{{1}}
答案 1 :(得分:1)
好的,所以你的Snot
变量Snit
可变。
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
来跟踪它们,然后其他数据结构只会使用弱引用 - 但这可能会变得丑陋快速),所以下一个最好的事情就是当它None
的任何一个消失时它变得等于Snit
。
我发现snits
和snots
都是list
s - 订单重要吗?如果顺序不重要,您可以使用set
代替,然后就可以有一个高性能的解决方案,其中实际上从数据结构中删除了死snot
- 但这会增加复杂性:每个Snot
都必须跟踪它所处的数据结构,并且每个Snit
都必须保留一个Snot
所在的列表,而魔法会有住在__del__
,可能导致其他问题......