91 votes

Objet Python se supprimant lui-même

Pourquoi cela ne fonctionne-t-il pas ? J'essaie de faire en sorte qu'une instance d'une classe se supprime elle-même.

>>> class A():
    def kill(self):
        del self

>>> a = A()
>>> a.kill()
>>> a
<__main__.A instance at 0x01F23170>

78voto

Jeremy Ruten Points 59989

Le "self" n'est qu'une référence à l'objet. del self" supprime la référence "self" de l'espace de noms local de la fonction kill, au lieu de l'objet lui-même.

Pour s'en convaincre, il suffit de regarder ce qui se passe lorsque ces deux fonctions sont exécutées :

>>> class A():
...     def kill_a(self):
...         print self
...         del self
...     def kill_b(self):
...         del self
...         print self
... 
>>> a = A()
>>> b = A()
>>> a.kill_a()
<__main__.A instance at 0xb771250c>
>>> b.kill_b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in kill_b
UnboundLocalError: local variable 'self' referenced before assignment

50voto

Ned Batchelder Points 128913

Il n'est pas nécessaire d'utiliser del pour supprimer les instances en premier lieu. Une fois que la dernière référence à un objet a disparu, l'objet est ramassé. Peut-être devriez-vous nous en dire plus sur le problème dans son ensemble.

46voto

les Points 827

Je crois que j'ai enfin trouvé !
NOTE : Vous ne devez pas utiliser cette fonction dans le code normal. mais c'est le cas possible . Il s'agit uniquement d'une curiosité, voir les autres réponses pour des solutions concrètes à ce problème.


Jetez un coup d'œil à ce code :

# NOTE: This is Python 3 code, it should work with python 2, but I haven't tested it.
import weakref

class InsaneClass(object):
    _alive = []
    def __new__(cls):
        self = super().__new__(cls)
        InsaneClass._alive.append(self)

        return weakref.proxy(self)

    def commit_suicide(self):
        self._alive.remove(self)

instance = InsaneClass()
instance.commit_suicide()
print(instance)

# Raises Error: ReferenceError: weakly-referenced object no longer exists

Lorsque l'objet est créé dans le __new__ l'instance est remplacée par un proxy de référence faible et la seule référence forte est conservée dans l'attribut de classe _alive.

Qu'est-ce qu'une référence faible ?

Une référence faible est une référence qui ne compte pas comme une référence lorsque le ramasse-miettes collecte l'objet. Prenons l'exemple suivant :

>>> class Test(): pass

>>> a = Test()
>>> b = Test()

>>> c = a
>>> d = weakref.proxy(b)
>>> d
<weakproxy at 0x10671ae58 to Test at 0x10670f4e0> 
# The weak reference points to the Test() object

>>> del a
>>> c
<__main__.Test object at 0x10670f390> # c still exists

>>> del b
>>> d
<weakproxy at 0x10671ab38 to NoneType at 0x1002050d0> 
# d is now only a weak-reference to None. The Test() instance was garbage-collected

La seule référence forte à l'instance est donc stockée dans l'attribut de classe _alive. Et lorsque la méthode commit_suicide() supprime la référence, l'instance est ramassée.

15voto

S.Lott Points 207588

Dans ce contexte spécifique, votre exemple n'a pas beaucoup de sens.

Lorsqu'un Être ramasse un objet, celui-ci conserve une existence individuelle. Il ne disparaît pas parce qu'il a été ramassé. Il existe toujours, mais il est (a) au même endroit que l'Être, et (b) ne peut plus être ramassé. Bien qu'il ait changé d'état, il existe toujours.

Il existe une association bidirectionnelle entre l'être et l'objet. L'être possède l'objet dans une collection. L'objet est associé à un être.

Lorsqu'un objet est ramassé par un être, deux choses doivent se produire.

  • L'Être comment ajoute l'Élément dans certains set d'articles. Votre bag par exemple, pourrait être un tel attribut set . [A list est un mauvais choix -- l'ordre importe-t-il dans le sac ?].

  • L'emplacement de l'objet passe de l'endroit où il se trouvait à l'endroit où se trouve l'être. Il existe probablement deux catégories d'objets : ceux qui ont un sens indépendant de l'emplacement (parce qu'ils se déplacent par eux-mêmes) et ceux qui doivent déléguer leur emplacement à l'être ou au lieu où ils se trouvent.

En aucun cas un objet Python ne doit être supprimé. Si un objet est "détruit", il n'est pas dans le sac de l'Être. Il n'est pas dans un emplacement.

player.bag.remove(cat)

C'est tout ce qu'il faut pour que le chat sorte du sac. Puisque le chat n'est utilisé nulle part ailleurs, il existera à la fois en tant que mémoire "utilisée" et n'existera pas parce que rien dans votre programme ne peut y accéder. Il disparaîtra tranquillement de la mémoire lorsqu'un événement quantique se produira et que les références de la mémoire seront ramassées.

D'autre part,

here.add( cat )
player.bag.remove(cat)

Place le chat à l'emplacement actuel. Le chat continue d'exister et ne sera pas mis à la poubelle.

7voto

Zachary Kraus Points 81

En réalité, vous ne devriez pas avoir besoin de supprimer l'objet pour faire ce que vous essayez de faire. Au lieu de cela, vous pouvez modifier l'état de l'objet. Pour illustrer ce principe sans entrer dans le codage, prenons l'exemple d'un joueur qui se bat contre un monstre et le tue. L'état de ce monstre est "fighting". Le monstre accède à toutes les méthodes nécessaires au combat. Lorsque le monstre meurt parce que sa santé tombe à 0, l'état du monstre passe à mort et votre personnage cesse automatiquement d'attaquer. Cette méthodologie est très similaire à l'utilisation de drapeaux ou même de mots-clés.

Apparemment, en Python, il n'est pas nécessaire de supprimer les classes, car elles sont automatiquement ramassées lorsqu'elles ne sont plus utilisées.

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