@@ -862,22 +862,27 @@ def replace_list(
862862 # This is ugly, but we have to get rid of intermediate refs. We
863863 # can simply clear the referenced_blocks if we already copied,
864864 # otherwise we have to remove ourselves
865- # GH#62787: Handle invalid weak references properly
866- self_blk_ids = {
867- id (ref_block ): i
868- for i , b in enumerate (self .refs .referenced_blocks )
869- if (ref_block := b ()) is not None
870- }
871- for b in result :
872- if b .refs is self .refs :
873- # We are still sharing memory with self
874- if id (b ) in self_blk_ids :
875- # Remove ourselves from the refs; we are temporary
876- self .refs .referenced_blocks .pop (self_blk_ids [id (b )])
877- else :
878- # We have already copied, so we can clear the refs to avoid
879- # future copies
880- b .refs .referenced_blocks .clear ()
865+ # GH#62787: Handle invalid weak references properly and robustly
866+ # Build a set of block ids from the current result that still share
867+ # the same refs object; those are temporary and should be removed
868+ # from referenced_blocks without relying on stale indices.
869+ to_remove_ids = {id (blk ) for blk in result if blk .refs is self .refs }
870+ if to_remove_ids :
871+ # Keep only live weakrefs not pointing to blocks we remove
872+ new_refs = []
873+ for wr in self .refs .referenced_blocks :
874+ obj = wr ()
875+ if obj is None :
876+ continue
877+ if id (obj ) in to_remove_ids :
878+ continue
879+ new_refs .append (wr )
880+ self .refs .referenced_blocks = new_refs
881+ # For blocks that have already copied, clear their refs to avoid
882+ # future copies.
883+ for blk in result :
884+ if blk .refs is not self .refs :
885+ blk .refs .referenced_blocks .clear ()
881886 new_rb .extend (result )
882887 rb = new_rb
883888 return rb
0 commit comments