@@ -844,6 +844,68 @@ def plot(self, i0=0, isub=1):
844844 show ()
845845
846846
847+ def print_cycles (objects , outstream = sys .stdout , show_progress = False ):
848+ """
849+ objects: A list of objects to find cycles in. It is often useful
850+ to pass in gc.garbage to find the cycles that are
851+ preventing some objects from being garbage collected.
852+ outstream: The stream for output.
853+ show_progress: If True, print the number of objects reached as they are
854+ found.
855+ """
856+ import gc
857+ from types import FrameType
858+
859+ def print_path (path ):
860+ for i , step in enumerate (path ):
861+ # next "wraps around"
862+ next = path [(i + 1 ) % len (path )]
863+
864+ outstream .write (" %s -- " % str (type (step )))
865+ if isinstance (step , dict ):
866+ for key , val in step .items ():
867+ if val is next :
868+ outstream .write ("[%s]" % repr (key ))
869+ break
870+ if key is next :
871+ outstream .write ("[key] = %s" % repr (val ))
872+ break
873+ elif isinstance (step , list ):
874+ outstream .write ("[%d]" % step .index (next ))
875+ elif isinstance (step , tuple ):
876+ outstream .write ("( tuple )" )
877+ else :
878+ outstream .write (repr (step ))
879+ outstream .write (" ->\n " )
880+ outstream .write ("\n " )
881+
882+ def recurse (obj , start , all , current_path ):
883+ if show_progress :
884+ outstream .write ("%d\r " % len (all ))
885+
886+ all [id (obj )] = None
887+
888+ referents = gc .get_referents (obj )
889+ for referent in referents :
890+ # If we've found our way back to the start, this is
891+ # a cycle, so print it out
892+ if referent is start :
893+ print_path (current_path )
894+
895+ # Don't go back through the original list of objects, or
896+ # through temporary references to the object, since those
897+ # are just an artifact of the cycle detector itself.
898+ elif referent is objects or isinstance (referent , FrameType ):
899+ continue
900+
901+ # We haven't seen this object before, so recurse
902+ elif id (referent ) not in all :
903+ recurse (referent , start , all , current_path + [obj ])
904+
905+ for obj in objects :
906+ outstream .write ("Examining: %r\n " % obj )
907+ recurse (obj , obj , { }, [])
908+
847909if __name__ == '__main__' :
848910 assert ( allequal ([1 ,1 ,1 ]) )
849911 assert (not allequal ([1 ,1 ,0 ]) )
0 commit comments