from typing import List # Same as previous exercise, but with the additional requirement # that whenever an object becomes garbage (unreachable), a finalizer # is immediately called on it. The finalizer may perform arbitrary # heap manipulation (as long as it is otherwise legal; in # particular, it may ‘re-animate’ the object it is finalizing, by # storing a reference to this object). A finalizer must not be # called on an object if a reference exists to this object (even if # that reference is from another dead object). class Heap: def add_root( self, obj ): pass def add_ref( self, obj_from, obj_to ): pass def del_ref( self, obj_from, obj_to ): pass def set_finalizer( self, callback ): pass def test_basic() -> None: h = Heap() h.add_root( 1 ) fin : List[ int ] = [] h.set_finalizer( lambda x: fin.append( x ) ) h.add_ref( 1, 2 ) h.add_ref( 1, 3 ) h.add_ref( 2, 3 ) h.add_ref( 3, 4 ) h.add_ref( 4, 5 ) h.del_ref( 3, 4 ) assert fin == [ 4, 5 ] h.add_ref( 3, 4 ) h.add_ref( 4, 5 ) h.set_finalizer( lambda x: h.add_ref( 1, x ) ) h.del_ref( 3, 4 ) h.set_finalizer( lambda x: fin.append( x ) ) h.del_ref( 1, 4 ) assert fin == [ 4, 5, 4, 5 ] h.del_ref( 1, 3 ) assert fin == [ 4, 5, 4, 5 ] h.del_ref( 1, 2 ) assert fin == [ 4, 5, 4, 5, 2, 3 ] if __name__ == '__main__': test_basic()