python delegates circular-reference

title python



Patrón de delegado de Python: ¿cómo evitar la referencia circular? (2)

¿Por qué no sería basura recogida al final? Cuando la secuencia de comandos termina y Python completa la ejecución, toda la sección de la memoria se marcará para la recolección de basura y (eventualmente) la recuperación del sistema operativo.

Si está ejecutando esto en un programa de larga ejecución, una vez que A y B son desreferenciados, la memoria será recuperada.

Me gustaría preguntar si el uso del Patrón de Delegados en Python daría lugar a referencias circulares y, de ser así, ¿cuál sería la mejor manera de implementarlo para garantizar que el objeto y su delegado sean recolectados?

En Objective C, el problema anterior se evita mediante el uso de una referencia débil al delegado. En C ++, no llamamos eliminar en el delegado. Encontré un enlace al módulo de referencia débil de Python aquí: http://docs.python.org/library/weakref.html . Parece que un enfoque plausible podría ser crear una referencia débil para referirse a la variable de instancia utilizando este módulo, pero no estoy seguro.

Como busqué en Google esta pregunta y no pude encontrar respuestas, me pregunto si esto es incluso un problema en Python o si hay una solución común (sin la necesidad del módulo weakref) que desconozco. ¿de? Además, busqué stackoverflow antes de preguntar, pero las preguntas que encontré tratan con importaciones circulares o un patrón de delegado en general y no específico para Python y el problema de las referencias circulares.

Gracias de antemano por cualquier respuesta.

A continuación se incluye un código para un ejemplo de juguete para ayudar a ilustrar mi pregunta. Implementé el código de esta manera y funciona, pero no estoy seguro de si la memoria es basura al final.

class A(object): def __init__(self): self.delegate = None # Some other instance variables that keep track of state for performing some tasks. def doSomething(self): if self.delegate is not None: self.delegate.doSomething() else: print(''Cannot perform task because delegate is not set.'') # Other methods not shown. class B(object): def __init__(self): self.a = A() # Need to keep object ''a'' from garbage collected so as to preserve its state information. self.a.delegate = self # Is this a circular reference? How to ''fix'' it so that A and B will eventually be garbage collected? def doSomething(self): print(''B doing something'') # Other methods not shown.

EDITAR :

Después de leer algunas de las respuestas, decidí aclarar mi pregunta. Entiendo que Python tiene recolección de basura. Lo que no estaba seguro era si realizaría recolección de basura en objetos de referencia circular. Mis preocupaciones surgen del siguiente pasaje del documento de Python:

Detalle de implementación de CPython: CPython actualmente utiliza un esquema de recuento de referencias con detección retardada (opcional) de basura cíclicamente vinculada, que recoge la mayoría de los objetos tan pronto como se vuelven inalcanzables, pero no se garantiza que recopile 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 vuelvan 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.

La siguiente publicación proporciona una explicación más clara sobre el problema de los objetos de referencia circular y por qué evitaría la recolección de basura en esos objetos (al menos en una configuración típica): http://www.electricmonk.nl/log/2008/07/07 / python-destructor-and-garbage-collection-notes / .

Además, me encontré con la respuesta de Alex Martellli a la siguiente pregunta sobre si los usuarios de Python deberían preocuparse por la referencia circular: ¿Debería preocuparme por las referencias circulares en Python? De su respuesta, deduzco que a pesar de que los objetos de referencia circular eventualmente serán basura recolectada PERO habría gastos generales. Si es significativo depende del programa.

Además, mencionó usar el módulo weakref de Python pero no dijo explícitamente cómo.

Por lo tanto, me gustaría agregar las siguientes preguntas para aclarar algunos problemas no resueltos:

  1. Los documentos dicen que la colección con guardapolvos no está garantizada para los objetos de referencia circular. Pero de las respuestas parece que no es el caso. 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 afirma en la respuesta de Alex y mi pregunta, ¿evitaría por completo el problema?

Una vez más, gracias por las respuestas.


Python ya hace la recolección de basura. Solo necesita hacer algo especial si escribe sus propios tipos de contenedor en C, como extensiones.

Demostración: ejecute este programa y observe cómo el uso de la memoria no sube.

class C(object): pass def circular(): for x in range(10**4): for y in range(10**4): a = C() b = C() a.x = b b.x = a circular()

Nota al pie: la siguiente función no hace nada, elimínela.

def setDelegate(self, delegate): self.delegate = delegate

En lugar de llamar a x.setDelegate(y) , puede usar x.delegate = y . Puede sobrecargar el acceso de los miembros en Python, por lo que no hay ningún beneficio al escribir un método.