6 votes

Python Delegate Pattern - Comment éviter la référence circulaire ?

Je voudrais savoir si l'utilisation du modèle de délégué en Python peut conduire à des références circulaires et, si c'est le cas, quelle serait la meilleure façon de l'implémenter pour s'assurer que l'objet et son délégué seront récupérés par les ordures ménagères ?

En Objective C, le problème ci-dessus est évité en utilisant une référence faible au délégué. En C++, on n'appelle pas delete sur le délégué. J'ai trouvé un lien vers le module de référence faible de Python ici : http://docs.python.org/library/weakref.html . Il semble qu'une approche plausible pourrait être de créer une référence faible pour se référer à la variable d'instance en utilisant ce module, mais je ne suis pas sûr.

Comme j'ai cherché sur Google et que je n'ai pas trouvé de réponse à cette question, je me demande si c'est un problème en Python ou s'il existe une solution commune (sans avoir besoin du module weakref) que je ne connais pas ? Par ailleurs, j'ai effectué une recherche sur stackoverflow avant de poser ma question, mais les questions que j'ai trouvées portaient soit sur les importations circulaires, soit sur le modèle de délégué en général, et non sur Python et le problème des références circulaires.

Merci d'avance pour toute réponse.

Vous trouverez ci-dessous le code d'un petit exemple pour illustrer ma question. J'ai implémenté du code de cette manière et cela fonctionne mais je ne suis pas sûr que la mémoire soit ramassée à la fin.

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 :

Après avoir lu certaines des réponses, j'ai décidé de clarifier ma question. Je comprends que Python dispose d'un système de garbage collection. Ce dont je n'étais pas sûr, c'est qu'il le fasse pour les objets à référence circulaire. Mes inquiétudes proviennent du passage suivant de la doc de Python :

Détail de l'implémentation de CPython : CPython utilise actuellement une avec une détection retardée (optionnelle) de la présence de détection retardée des ordures cycliques, qui collecte la plupart des objets dès qu'ils deviennent inaccessibles, mais est pas de garantie de collecte des déchets contenant des références circulaires . Voir la documentation du module gc pour des informations sur le contrôle de la collecte des ordures cycliques. D'autres implémentations de implémentations agissent différemment et CPython peut changer. Ne dépendez pas de la finalisation immédiate des objets lorsqu'ils deviennent inaccessibles (ex : toujours fermer les fichiers).

Le passage dans sa forme originale peut être trouvé ici : http://docs.python.org/reference/datamodel.html La mise en gras est de moi.

L'article suivant fournit une explication plus claire du problème des objets à référence circulaire et de la raison pour laquelle il empêche la collecte des déchets sur ces objets (du moins dans un contexte typique) : http://www.electricmonk.nl/log/2008/07/07/python-destructor-and-garbage-collection-notes/ .

Par ailleurs, je viens de tomber sur la réponse d'Alex Martellli à la question suivante : les utilisateurs de Python doivent-ils s'inquiéter de la référence circulaire ? Dois-je m'inquiéter des références circulaires en Python ? D'après sa réponse, j'en déduis que même si les objets à référence circulaire seront éventuellement récupérés, il y aura des frais généraux. Le fait que cela soit significatif dépend du programme.

De plus, il a mentionné l'utilisation du module weakref de Python mais n'a pas dit explicitement comment.

C'est pourquoi j'aimerais ajouter les questions suivantes afin de clarifier certains points non résolus :

  1. La documentation indique que la collecte de déchets n'est pas garantie pour les systèmes circulaires. objets référencés circulairement. Mais d'après les réponses, il semble que ce ne soit pas le cas. pas le cas. Alors, ai-je mal compris le passage ou y a-t-il d'autres détails que j'ai manqués ?
  2. Je suppose qu'utiliser une référence faible, comme indiqué dans la réponse d'Alex et ma question, permettrait d'éviter complètement le problème de l'overhead ?

Encore une fois, merci pour les réponses.

4voto

Dietrich Epp Points 72865

Python fait déjà du garbage collection. Vous ne devez faire quelque chose de spécial que si vous écrivez vos propres types de conteneurs en C, comme des extensions.

Démonstration : Exécutez ce programme et observez l'utilisation de la mémoire pas monter.

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()

Note de bas de page : La fonction suivante ne fait rien, supprimez-la.

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

Au lieu d'appeler x.setDelegate(y) vous pouvez utiliser x.delegate = y . Vous pouvez surcharger l'accès aux membres en Python, il n'y a donc aucun avantage à écrire une méthode.

0voto

Jordan Points 12780

Pourquoi ne serait-il pas collecté à la fin ? Lorsque le script est terminé et que python termine son exécution, la section entière de la mémoire sera marquée pour le ramassage des ordures et (éventuellement) la récupération par le système d'exploitation.

Si vous l'exécutez dans un programme long, une fois que A et B sont tous deux déréférencés, la mémoire sera récupérée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X