Print loops of cyclic references in the given *objects*. It is often useful to pass in ``gc.garbage`` to find the cycles that are preventing some objects from being garbage collected. Parameters ---------- objects A list of objects to find cycles in. outstream
(objects, outstream=sys.stdout, show_progress=False)
| 738 | |
| 739 | |
| 740 | def print_cycles(objects, outstream=sys.stdout, show_progress=False): |
| 741 | """ |
| 742 | Print loops of cyclic references in the given *objects*. |
| 743 | |
| 744 | It is often useful to pass in ``gc.garbage`` to find the cycles that are |
| 745 | preventing some objects from being garbage collected. |
| 746 | |
| 747 | Parameters |
| 748 | ---------- |
| 749 | objects |
| 750 | A list of objects to find cycles in. |
| 751 | outstream |
| 752 | The stream for output. |
| 753 | show_progress : bool |
| 754 | If True, print the number of objects reached as they are found. |
| 755 | """ |
| 756 | import gc |
| 757 | |
| 758 | def print_path(path): |
| 759 | for i, step in enumerate(path): |
| 760 | # next "wraps around" |
| 761 | next = path[(i + 1) % len(path)] |
| 762 | |
| 763 | outstream.write(" %s -- " % type(step)) |
| 764 | if isinstance(step, dict): |
| 765 | for key, val in step.items(): |
| 766 | if val is next: |
| 767 | outstream.write(f"[{key!r}]") |
| 768 | break |
| 769 | if key is next: |
| 770 | outstream.write(f"[key] = {val!r}") |
| 771 | break |
| 772 | elif isinstance(step, list): |
| 773 | outstream.write("[%d]" % step.index(next)) |
| 774 | elif isinstance(step, tuple): |
| 775 | outstream.write("( tuple )") |
| 776 | else: |
| 777 | outstream.write(repr(step)) |
| 778 | outstream.write(" ->\n") |
| 779 | outstream.write("\n") |
| 780 | |
| 781 | def recurse(obj, start, all, current_path): |
| 782 | if show_progress: |
| 783 | outstream.write("%d\r" % len(all)) |
| 784 | |
| 785 | all[id(obj)] = None |
| 786 | |
| 787 | referents = gc.get_referents(obj) |
| 788 | for referent in referents: |
| 789 | # If we've found our way back to the start, this is |
| 790 | # a cycle, so print it out |
| 791 | if referent is start: |
| 792 | print_path(current_path) |
| 793 | |
| 794 | # Don't go back through the original list of objects, or |
| 795 | # through temporary references to the object, since those |
| 796 | # are just an artifact of the cycle detector itself. |
| 797 | elif referent is objects or isinstance(referent, types.FrameType): |