madpython <[EMAIL PROTECTED]> wrote: > 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.
And the latter issue is what the use of weakref in both responses was about. > 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) Note that this is quite sloppy: -- test "if ainst is None:" -- no excuse to use just "if ainst:" -- at the end of the loop ainst remains bound -- "del ainst" to avoid ainst being an extra reference to the instance neither of these explains your bug, but -- just tighten up your code, it's a good idea!-) > > for i in range(5): > instList.remove(instList[0]) #here the hardref is deleted SUPER sloppy! Just "del instList[0]" for the same effect much better obtained. > ainst=A() > while not ainst: > #make shure that ainst is not NoneType Again, "while ainst is None:" would be far better. > gc.collect() > time.sleep(1) #wait 1 sec for gc() to clean the memory Useless, gc.collect() is synchronous *AND* only cleans up CYCLIC garbage anyway -- unless instances of A have reference loops, both lines are useless (the sleep is useless in ANY case). > 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. Your test code below does NOT do what your code here does! Instead it removes (in the worst possible way, rather than cleanly, but, no matter) a RANDOM reference -- which may happen to be the same as "item" had left over from the previous run... because of a printing loop that is in your sample below and not here... which is where the sloppiness catches up on you. Specifically, look at this code from the sample that you had below: > #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 "*", len(instList), len(A._weakrefdict) > instList.append(ainst) > for item in instList: > print item.getId()," -- ",item.instCounter > #print "-------> ",item > print "++++++++++++++++++++++++++++" after the printing loop, name 'item' remains bound to the object that is last element of instList -- so if that one just happens to be the element you remove in that horrid first line of the main (outer) loop, 5 instances of class A nevertheless remain alive and therefore ainst will be None forevermore, despite all the useless calls to gc.collect and sleep. A decent way to code this functionality would be: # delete and recreate an arbitrary element in the instList for i in range(len(instList)): del instList[random.randrange(len(instList))] instList.append(A()) for item in instList: print item.getId()," -- ",item.instCounter del item print "++++++++++++++++++++++++++++" It would be nice to also print len(instList) and the length of the weakref dictionary of class A, to doublecheck things, but you've made life extremely hard for yourself by naming the latter with TWO leading underscores instead of one, thus asking Python to name-mangle it to make it very inconvenient to access. Avoid the two-leading-underscores construct (use just ONE leading underscore -- no mangling, no problems) unless and until you are positive that you know exactly what you're doing and are certain that you need the two underscores in a given specific case -- do *NOT* "default" to using two underscores and make life uselessly hard for yourself in terms of introspection and debugging. And, read up on such issues as "del somelist[index]" being WAY better than "somelist.remove(somelist[index])" and the way names, references, objects and garbage collection work in Python... Alex -- http://mail.python.org/mailman/listinfo/python-list