¿Puede la recolección de basura de Python garantizar la recuperación de objetos de referencia circulares en cualquier circunstancia?

Esta pregunta es una extensión de una pregunta que formulé anteriormente: Patrón de delegado de Python: ¿Cómo evitar la referencia circular? Después de leer las respuestas, decidí aclarar mi pregunta, pero se me pidió que la publicara por separado.

Aquí va:

  1. Un pasaje en los documentos de Python (reproducidos a continuación) indica que la colección de garbaged no está garantizada para los objetos de referencia circulares. Un post que encontré aquí sugiere lo mismo. Pero las respuestas a mi pregunta anterior no están de acuerdo. Entonces, ¿he entendido mal el pasaje o hay más detalles que me he perdido?
  2. Supongo que usar una referencia débil, como se indica en la respuesta de Alex Martelli a la pregunta ¿Debo preocuparme por las referencias circulares en Python? ¿Evitaría por completo la sobrecarga de objetos de referencia circulares de recolección de basura mencionados en su respuesta? ¿Si es así, cómo funciona?

Los documentos relevantes de Python que sugieren un siguiente pasaje conflictivo del documento de Python:

Detalle de la implementación de CPython: CPython actualmente utiliza un esquema de conteo de referencias con (opcional) detección retardada de basura enlazada cíclicamente, que recolecta la mayoría de los objetos tan pronto como se vuelven inalcanzables, pero no se garantiza que recolecte basura que contenga referencias circulares . Consulte la documentación del módulo gc para obtener información sobre cómo controlar la recolección de basura cíclica. Otras implementaciones actúan de manera diferente y CPython puede cambiar. No dependa de la finalización inmediata de los objetos cuando se vuelven inalcanzables (por ejemplo, siempre cierre los archivos).

El pasaje en su forma original se puede encontrar aquí: http://docs.python.org/reference/datamodel.html La configuración en negrita es mía.

Gracias de antemano por cualquier respuesta.

Creo que la razón más importante por la que no se garantiza que se recopilen los objetos con referencias circulares es que, por diseño, Python nunca recostack objetos con referencias circulares si definen un método __del__ . Hay una razón bastante directa :

Python no recostack dichos ciclos automáticamente porque, en general, no es posible que Python adivine un orden seguro para ejecutar los __del__() .

Soy reacio a decir que esta es la única razón por la que los objetos inalcanzables con referencias circulares pueden no ser detectados. Probablemente hay algunas situaciones inusuales que podrían frustrar los mecanismos de detección del ciclo del GC. Pero a menos que defina __del__ para uno de sus objetos, probablemente esté bien. Simplemente no se preocupe por eso, y use las amplias opciones de depuración del GC si ve problemas de rendimiento.

Cuando dice que no está garantizado para recostackr referencias circulares, eso es exactamente lo que significa. Cuando las estructuras de datos contienen referencias circulares, el recuento de referencias siempre será distinto de cero, lo que significa que el recuento de referencias por sí solo no es suficiente para decidir cuándo eliminarlos. Por otro lado, encontrar todas las referencias circulares después de llegar al final de cada scope llevaría mucho tiempo, por decir lo menos. Implicaría analizar las relaciones de todos los objetos con un recuento de referencia distinto de cero.

Dicho esto, no espero que tenga un problema con eso, en general. Para un script ligero, puedes ignorarlo. Para otros, todavía tiene que hacer un trabajo de limpieza al final del scope (cerrar un archivo o incluso eliminar la referencia circular), como lo haría en C, por ejemplo, pero aún no es tan embriagador como C.

Si se convierte en un problema, simplemente elimine la referencia circular antes de terminar con cada objeto de datos.