[英]How can I retrieve the instance of a class from a value of one of its attributes?
[英]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_list
的Snit
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
),具有以下行為:
Snot
任何一個Snit
消失(當沒有強引用時), Snot
也應該消失(這就是為什么我將s1
, s2
等設置為弱引用)。 請注意, Snot
可能已使用Snit
或1個Snit
進行初始化。 Snit
的數量並不重要, Snit
的死亡是最重要的。 Snit
的引用的任何一個Snot
消失,則Snit
仍然存在。 Snot
,包含對Snot
對象的引用的數據結構也會更新( Snot
得到pop
) 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路Snit
, YellowSnot
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
好的,所以你有一個具有可變數量的Snit
的Snot
。
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
。
我看到snits
和snots
都是list
s - 順序重要嗎? 如果順序不重要,你可以使用set
s,然后就可以有一個高性能的解決方案,其中死的snot
實際上從數據結構中刪除 - 但它會增加復雜性:每個Snot
都必須跟蹤它Snit
數據結構,每個Snit
都必須保留一個Snot
s所在的列表,並且魔法必須存在於__del__
,這可能會導致其他問題......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.