簡體   English   中英

當其中一個屬性變為死時,自動刪除類實例

[英]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=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 list (一個snit_list ):

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

現在我使用我的snit_listSnit s列出了Snot

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>

這不能忍受! 一個帶有死Snit Snot - 顯然 - 完全是胡說八道。

所以我真的希望任何對Snot引用在其一個或多個Snit被破壞后至少返回為None 但理想情況下,將Snot自動從snot_list列表中刪除會更好( len(snot_list)因刪除的Snot數量而縮小)。

有什么好辦法解決這個問題?

澄清:

Snot是一個對象,只有在有一組有效的Snit時才存在(“有效”表示它具有相同數量的已初始化的Snit ),具有以下行為:

  1. 如果Snot任何一個Snit消失(當沒有強引用時), Snot也應該消失(這就是為什么我將s1s2等設置為弱引用)。 請注意, Snot 可能已使用Snit或1個Snit進行初始化。 Snit的數量並不重要, Snit死亡是最重要的。
  2. 如果包含對Snit的引用的任何一個Snot消失,則Snit仍然存在。
  3. 可選:當刪除一個Snot ,包含對Snot對象的引用的數據結構也會更新( Snot得到pop
  4. 可選:當所有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 s列表而不是讓Snot成員為弱引用(盡管我沒有看到這些變化中的任何一個會如何改善事情)。

我也曾考慮創建Snot子類- ClearSnot 1路SnitYellowSnot 2 Snit S, GreenSnot 3 Snit S,等我不確定這是否會令事情變得更容易維護,或更加困難。

沒有什么是真正的自動化。 您需要擁有一個手動運行的函數來檢查死Snit ,或者有一個函數是Snot一部分,只要Snot發生任何有趣的事情就會被調用,並刪除死Snit s。

例如:

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____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

好的,所以你有一個具有可變數量的SnitSnot

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消失時,它將變得等於None


我看到snitssnots都是list s - 順序重要嗎? 如果順序不重要,你可以使用set s,然后就可以有一個高性能的解決方案,其中死的snot實際上從數據結構中刪除 - 但它會增加復雜性:每個Snot都必須跟蹤它Snit數據結構,每個Snit都必須保留一個Snot s所在的列表,並且魔法必須存在於__del__ ,這可能會導致其他問題......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM