Search code examples
pythongarbage-collectiondestructorreference-counting

Method call after garbage collection is finished


I have a class "Foo" where the objects are registered in an object called FooManager. After the scope of a function is left the Foo objects can only be deleted if I know ALL the Foos which are "tagged for deletion".

class FooManager:
    
    def __init__(self):
        self.deletion_list = []
    
    def delete_tagged_foos(self):
        #Deletion process
        pass

class Foo:

    def __init__(self, FooManager):
        self.FooManager = FooManager

    def __del__(self):
        self.FooManager.deletion_list.append(self)

        if garbage_collection_finished():
            self.FooManager.delete_tagged_foos()


def foo_processing(manager):
    foo1 = Foo(manager)
    foo2 = Foo(manager)
    foo3 = Foo(manager)
    
    # Tag foo2 and foo3 for deletion (but not foo1)
    # and perform deletion process once every foo is tagged
    return foo1


manager = FooManager()

foo1 = foo_processing(manager)

How can I acquire the boolean garbage_collection_finished()?


Solution

  • How about keeping track of foo instances in the FooManager and using it as a decorator on functions that create temporary foo instances:

    import sys
    
    class FooManager:
        
        def __init__(self):
            self.foos = []
    
        def registerFoo(self,foo):
            foo.FooManager = self
            self.foos.append(foo)
            print("+1")
    
        def cleanFoos(self,func):
            def callFunc(*args,**kwargs):
                result = func(*args,**kwargs)
                # 3 refs = self.foos, foo in comprehension, getrefcount param
                orphanFoos = [foo for foo in self.foos if sys.getrefcount(foo)<=3]
                # process orphans as needed
                # leave them in self.foos if they are not to be deleted
                self.foos  = [foo for foo in self.foos if foo not in orphanFoos]
                # ...
                print("foo count:",len(self.foos))
                return result 
            return callFunc
            
    class Foo:
    
        def __init__(self, FooManager):
            FooManager.registerFoo(self)
    
        def __del__(self): print("deleted")
    

    usage:

    manager = FooManager()
    
    @manager.cleanFoos
    def foo_processing(manager):
        foo1 = Foo(manager)
        foo2 = Foo(manager)
        foo3 = Foo(manager)
        
        # Tag foo2 and foo3 for deletion (but not foo1)
        # and perform deletion process once every foo is tagged
        return foo1
    
    foo1 = foo_processing(manager)
    

    output:

    +1
    +1
    +1
    foo count: 1
    deleted
    deleted