Python 当类实例的某个属性失效时自动删除该类实例 设置
假设我有一个Python 当类实例的某个属性失效时自动删除该类实例 设置,python,Python,假设我有一个Snit: class Snit(): pass snot_list[0].s4 # <weakref at 0x00BlahBlah; dead> 和一个Snot,其中包含对多达四个Snit的弱引用: import weakref class Snot(): def __init__(self,s1=None,s2=None,s3=None,s4=None): self.s1 = weakref.ref(s1) self.s2
Snit
:
class Snit(): pass
snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>
和一个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的list
(一个Snit\u list
):
现在,我使用我的Snit\u列表中的Snit
s创建了一个Snot
s列表:
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)
但是现在我有一个鼻涕和一个死鼻涕挂在那里:
class Snit(): pass
snot_list[0].s4 # <weakref at 0x00BlahBlah; dead>
但是,如果这太难,我可以:
assert snots[12] == None
assert snots[45] == None
我愿意改变一些事情。例如,如果它使设计更容易,我认为可以删除对Snit
s的弱引用,或者将它们移动到Snit
s的列表中,而不是让Snot
成员成为弱引用(尽管我看不出这两个更改如何改善情况)
我还考虑过用1Snit
创建Snot
子类-clearnot
,用2Snit
创建YellowSnot
,用3Snit
创建GreenSnot
子类,等等。我不确定这是否会使维护更容易,或者更困难 没有什么是真正自动的。您需要手动运行一个函数来检查死掉的Snit
s,或者需要一个属于Snot
的函数,该函数在Snot
发生任何有趣的事情时调用,以检查并移除死掉的Snit
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
例如:
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
有趣的部分是添加对\u remove\u dead\u snits
的调用,用于与Snot
进行每一次有趣的交互,例如\u getitem\uuuuuuuuu
,\uuuuu iter\uuuuuuuuuu
,以及您可以对其执行的任何其他操作
实际上,再仔细想想,如果每个Snot
只有四个可能的Snit
s,那么可以使用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
好的,你有一个Snot
,有一个可变的Snit
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
我看到snit
和snot
都是list
s——顺序重要吗?如果顺序不重要,您可以使用set
s来代替,这样就可以有一个性能解决方案,其中死的snot
实际上从数据结构中删除,但这会增加复杂性:每个snot
都必须跟踪它所处的数据结构,每一个Snit都必须保留一个列表,上面列出了它所在的Snot,而魔法必须存在于Snot中,这可能会导致其他问题……如果有人想知道这个问题是否仅仅是使用Snot工厂的一个策略,答案可能是肯定的。简言之,Snit不是您能否澄清一下,您是否希望访问已删除的属性Snitsnots[0]。s4
返回None,Snot本身在缺少成员时返回None,或者其他什么?您的澄清令人困惑。)根据你的例子,鼻涕12有三个鼻涕,但是当你删除其中一个鼻涕时,整个鼻涕就失效了?对不起,是的。我将更好地澄清并删除此评论,但是,是的,一旦创建它的Snit
中的任何一个被删除后,Snit
就不应该再存在了(尽管它可以更改为列表中的另一个Snit
)。我曾想过做一些与您上一段描述的类似的事情,但没有考虑使用集合。顺序并不一定重要,但如果没有某种顺序,我不知道在构建Snot
时如何引用每个特定的Snit
(而不仅仅是引用Snit\u列表中的索引)。我得再考虑一下。@RickTeachey:这一点很好,snits
必须保持一个列表,但是如果snots
可以成为一个set
…我想我可以生活在一个Snot
的集合中。现在来了解如何跟踪对象实例中的Snot
引用。这里是我唯一想到的一个想法:参考这里的另一个问题:Snot
实际上只是一个专门的Snit
容器。也许我应该编写一个通用容器(如您描述的performant解决方案),并将其子类化为Snot
、SnitList
和SnotList
。Snot
保存Snit
s,SnitList
也保存Snit
s,SnotList
(或set
,无论什么)保存Snot
s。