2014-11-20 53 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

相關問題