How to create a limited set of instanceses of a class

madpython madpython at gmail.com
Sun Jul 2 04:32:09 EDT 2006


Thanks Alex and Scott for your lead. It would've taken me forever
trying to figure it out by myself :)

I am affraid I didn't specify initially one thing and that led to a
confusion: there is no need to pick an instance from the weakref
dictionary, just return None if there are already 5 instances. But on
the other hand if a hardref to an object was deleted, it's place can be
taken by another one.
Here's what i mean (and where the problem is):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#build a list of 5 elements
instList=[]
for i in range(7):
	ainst=A()
	if ainst:
		instList.append(ainst)

for i in range(5):
	instList.remove(instList[0]) #here the hardref is deleted
	ainst=A()
	while not ainst:
		#make shure that ainst is not NoneType
		gc.collect()
		time.sleep(1)	#wait 1 sec for gc() to clean the memory
		ainst=A()	#try again
	instList.append(ainst) #new object added
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
the priblem is that ~3 out of 10 times the test part run into infinite
loop because of unsatisfied condition (while not ainst:) - memory
cannot be freed therefore new instance of A isn't permitted.


#!/usr/bin/env python
import weakref,random
import types,gc
import time
class Limited5(object):
    __weakrefdict=weakref.WeakValueDictionary()
    def __new__(cls,*args,**kwargs):
        if len(cls.__weakrefdict)<5:
            instance=super(Limited5,cls).__new__(cls,*args,**kwargs)
            cls.__weakrefdict[id(instance)]=instance
            return instance
#        return random.choice(cls.__weakrefdict.values())
        return None #no need to pick an instance
class A(Limited5):
    counter=0
    def __init__(self):
        self.instCounter=self.counter
        A.counter+=1
    def getId(self):
        return id(self)

if __name__=="__main__":
    instList=[]
    # populate the initial list of objects
    #make shure that there are only 5 elements
    for item in range(7):
        ainst=A()
        if hasattr(ainst,"getId"):
	    print ainst.getId()," -- ",ainst.instCounter
            instList.append(ainst)
    print "---------------------------------------------"

    #delete and recreate an arbitrary element in the instList
    for i in range(len(instList)):
        instList.remove(instList[random.choice(range(len(instList)))])
        ainst=A()
        while not ainst:        #here is an unstable part
            ainst=A()           #sometimes the loop becomes infinite
            print gc.collect()  #decpite the explicit call for gc() to
start
            time.sleep(1)
            print "*",
        instList.append(ainst)
        for item in instList:
            print item.getId()," -- ",item.instCounter
            #print "-------> ",item
        print "++++++++++++++++++++++++++++"




More information about the Python-list mailing list