2014-11-20 77 views
3

设置

说我有一个Snit自动删除类的实例时,它的属性中的一个变成死

class Snit(): pass 

而一个Snot,其中包含了,比如说弱引用,四Snit小号:

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

Snit S(snit_list因为它是)一个list

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

现在我做的使用Snit小号Snot个名单在我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是 - 显然 - 总废话。

所以我真的很想在的一个或多个销毁后,至少返回None作为Snot的任何引用。但理想情况下,Snot会自动从snot_list列表中移除(len(snot_list)缩小删除的Snot s的数量)会更好。

这是怎么回事?

澄清:

Snot是一个对象时,有一组有效的Snit S(“有效”意味着它具有相同数量的定义Snit的s时,有初始化所用)应仅存在,用以下行为:

  1. 如果在Snot任何一个Snit消失(没有强引用保持),该Snot也应该消失(这就是为什么我设置了s1s2等是弱引用)。请注意,Snot可能已用4,3,2或1 Snit初始化。 Snit s的数量并不重要,的死亡Snit是重要的。
  2. 如果包含对Snit的引用的任何一个Snot消失,则保留Snit
  3. OPTIONAL:当一个Snot被删除,含有参考Snot对象的数据结构被更新,以及(在Snot得到pop PED)
  4. OPTIONAL:当ALL引用该Snots一定Snit都消失,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) 
#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子类 - , S,GreenSnot3 Snit`s,等我不确定这是否会令事情变得更容易维护,或更加困难。

+0

如果任何人想知道这个问题是否仅仅是使用snot_factory的策略,答案可能是肯定的。 – 2014-11-20 23:11:50

+0

简而言之,没有。 ;-) – martineau 2014-11-20 23:22:49

+0

你能说清楚你是否想要访问被删除的属性Snit'snots [0] .s4'返回None,Snot本身在成员丢失时返回None,还是其他? – bjornsen 2014-11-20 23:27:12

回答

2

没有什么是真正的自动。您需要有一个手动运行的功能来检查死亡Snit s,或者有一个功能是Snot的一部分,该功能在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为与Snot每一个有趣的互动 - 比如__getitem____iter__,和其他任何你可以用它做什么。


事实上,更多地考虑这一点,如果你只按每个Snot有四个可能的Snit是你可以使用一个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

好了,你有Snot与可变量s。

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 s消失时,它将变成None


我看到snitssnots都是list秒 - 是为了重要?如果订单不重要,则可以使用set s,然后可以有一个高性能解决方案,其中snot实际上已从数据结构中移除 - 但这会增加复杂性:每个Snot都必须跟踪其中的数据结构是,并且每个Snit将不得不保留它在哪个Snot s的列表,并且该魔法将不得不住在__del__中,这可能导致其他问题...

+0

我曾想过像你最后一段描述的那样做,但没有考虑使用set。顺序不一定非常重要,虽然没有某种顺序,但我不知道如何在构建Snot时指向每个特定的'Snit'(而不是仅仅指它在'snit_list'中的索引)。我将不得不考虑更多。 – 2014-11-21 15:43:07

+1

@RickTeachey:好点 - 'snits'必须保留一个'list',但是如果'snots'可以成为'set' ... – 2014-11-21 18:39:41

+0

我想我可以忍受一个'Snot'set单曲。 – 2014-11-21 18:59:59

相关问题