monty 0.0.21

A sandboxed, snapshotable Python interpreter written in Rust.
Documentation
# A captured dataclass default can reach back to the class that captured it,
# making `__dataclass_fields__` part of a reference cycle:
#
#   Cyclic  ->  Field `b`  ->  default `box`  ->  box.owner  ->  Cyclic
#
# The cycle collector must therefore walk a `Field`'s captured default as its
# child. An instance is an accepted default because dataclasses reject them by
# *hashability*, and a class defining no `__eq__`/`__hash__` hashes by identity.
from dataclasses import dataclass


class Box:
    def __init__(self) -> None:
        self.owner = None


box = Box()


@dataclass
class Cyclic:
    a: int
    b: object = box


box.owner = Cyclic

assert Cyclic(1).b is box
assert Cyclic(1).b.owner is Cyclic

# `box`: the global, the class namespace entry `Cyclic.b`, and the `Field`'s
# captured default. `Cyclic`: the global plus `box.owner`. `Box`: the global plus the
# class reference every instance holds.
# ref-counts={'box': 3, 'Cyclic': 2, 'Box': 2}