Suppression de l'objet Python
pourquoi ça ne marche pas? J'essaie de faire un exemple de suppression de classe.
>>> class A():
def kill(self):
del self
>>> a = A()
>>> a.kill()
>>> a
<__main__.A instance at 0x01F23170>
11 réponses
"self" est seulement 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 réel.
pour vous en rendre compte, regardez 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
vous n'avez pas besoin d'utiliser del pour supprimer des instances en premier lieu. Une fois que la dernière référence à un objet disparu, l'objet sera d'ordures collectées. Vous devriez peut-être nous en dire plus sur le problème.
dans ce contexte précis, votre exemple n'a pas beaucoup de sens.
Lorsqu'un être ramasse un objet, celui-ci conserve une existence individuelle. Elle ne disparaît pas parce qu'elle a été ramassée. 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 subi un changement d'état, il existe toujours.
il y a une association bidirectionnelle entre L'être et L'objet. L'Être est l'Élément dans une collection. L'Élément est associé à un Être.
quand un objet est ramassé par un être, deux choses doivent se produire.
-
L'Être comment ajoute l'Élément dans certains
set
d'éléments. Votre attributbag
, par exemple, pourrait être un telset
. [Unlist
est un mauvais choix -- est de l'ordre de la matière dans le sac?] -
l'emplacement de L'article change de l'endroit où il sert à être à l'Être. Il y a probablement deux classes d'éléments os - ceux qui ont un sens indépendant de l'emplacement (parce qu'ils se déplacent par eux-mêmes) et les éléments qui doivent déléguer l'emplacement à l'être ou à l'endroit où ils sont assis.
en aucun cas un objet Python n'a besoin d'être supprimé. Si un objet est "détruit", il n'est pas dans le sac d'un être. Il n'est pas dans un lieu.
player.bag.remove(cat)
est tout ce qui Est nécessaire pour laisser sortir le chat du sac. Puisque le cat n'est utilisé nulle part ailleurs, il existera 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 quand un événement quantique se produit et les références de mémoire sont des déchets recueillis.
d'autre part,
here.add( cat )
player.bag.remove(cat)
placera le chat à l'emplacement actuel. Le chat continue d'exister, et ne sera pas mis avec la poubelle.
je crois que je l'ai enfin!
NOTE: vous ne devez pas utiliser ce code dans le code normal , mais il est possible .
Prendre un coup d'oeil a 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éé selon la méthode __new__
, l'instance est remplacée par un mandataire de référence faible et une seule référence est conservée dans l'attribut de classe _alive.
qu'est Ce qu'un la faiblesse de référence?
faible-référence est une référence qui ne compte pas comme une référence lorsque le ramasseur d'ordures 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
ainsi la seule référence forte à l'instance est stockée dans la classe _alive attribute. Et lorsque la méthode commit_suicide () supprime la référence, l'instance est ramassée.
de façon Réaliste, vous ne devez pas supprimer l'objet à faire ce que vous essayez de faire. Au lieu de cela vous pouvez changer l'état de l'objet. Un exemple de la façon dont cela fonctionne sans entrer dans le codage serait votre joueur se battant contre un monstre et tuer le monstre. L'état de ce monstre de combat. Le monstre aura accès à toutes les méthodes nécessaires pour se battre. Quand le monstre meurt parce que sa santé tombe à 0, l'état des monstres changera à mort et votre personnage sera cesser d'attaquer automatiquement. Cette méthodologie est très similaire à l'utilisation de drapeaux ou même de mots clés.
aussi apparemment en Python supprimer des classes n'est pas nécessaire car ils seront ramassés automatiquement quand ils ne sont plus utilisés.
j'essaie la même chose. J'ai un système de combat RPG dans lequel ma fonction de mort(self) doit tuer le propre objet de la classe de combat. Mais il semble que ce ne soit pas possible. Peut-être que mon jeu de classe dans lequel je rassemble tous les participants au combat devrait supprimer les unités de la carte "fictive"???
def Death(self):
if self.stats["HP"] <= 0:
print("%s wounds were too much... Dead!"%(self.player["Name"]))
del self
else:
return True
def Damage(self, enemy):
todamage = self.stats["ATK"] + randint(1,6)
todamage -= enemy.stats["DEF"]
if todamage >=0:
enemy.stats["HP"] -= todamage
print("%s took %d damage from your attack!"%(enemy.player["Name"], todamage))
enemy.Death()
return True
else:
print("Ineffective...")
return True
def Attack(self, enemy):
tohit = self.stats["DEX"] + randint(1,6)
if tohit > enemy.stats["EVA"]:
print("You landed a successful attack on %s "%(enemy.player["Name"]))
self.Damage(enemy)
return True
else:
print("Miss!")
return True
def Action(self, enemylist):
for i in range(0, len(enemylist)):
print("No.%d, %r"%(i, enemylist[i]))
print("It`s your turn, %s. Take action!"%(self.player["Name"]))
choice = input("\n(A)ttack\n(D)efend\n(S)kill\n(I)tem\n(H)elp\n>")
if choice == 'a'or choice == 'A':
who = int(input("Who? "))
self.Attack(enemylist[who])
return True
else:
return self.Action()
Je ne peux pas vous dire comment cela est possible avec les classes, mais les fonctions peuvent se Supprimer elles-mêmes.
def kill_self(exit_msg = 'killed'):
global kill_self
del kill_self
return exit_msg
et voir la sortie:
>>> kill_self
<function kill_self at 0x02A2C780>
>>> kill_self()
'killed'
>>> kill_self
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
kill_self
NameError: name 'kill_self' is not defined
Je ne pense pas que supprimer une instance individuelle d'une classe sans en connaître le nom soit possible.
NOTE: Si vous assignez un autre nom à la fonction, l'autre nom fera quand même référence à l'ancien, mais causera des erreurs une fois vous tentez de l'exécuter:
>>> x = kill_self
>>> kill_self()
>>> kill_self
NameError: name 'kill_self' is not defined
>>> x
<function kill_self at 0x...>
>>> x()
NameError: global name 'kill_self' is not defined
en effet, Python collecte les ordures par comptage de référence. Dès que la dernière référence à un objet est hors de portée, il est supprimé. Dans votre exemple:
a = A()
a.kill()
Je ne crois pas qu'il y ait moyen pour la variable " a " de se fixer implicitement à aucune.
si vous utilisez une seule référence à l'objet, alors l'objet peut se tuer en réinitialisant cette référence extérieure à lui-même, comme dans:
class Zero:
pOne = None
class One:
pTwo = None
def process(self):
self.pTwo = Two()
self.pTwo.dothing()
self.pTwo.kill()
# now this fails:
self.pTwo.dothing()
class Two:
def dothing(self):
print "two says: doing something"
def kill(self):
Zero.pOne.pTwo = None
def main():
Zero.pOne = One() # just a global
Zero.pOne.process()
if __name__=="__main__":
main()
vous pouvez bien sûr faire le contrôle logique en vérifiant l'existence de l'objet depuis l'extérieur de l'objet (plutôt que l'état de l'objet), comme par exemple dans:
if object_exists:
use_existing_obj()
else:
obj = Obj()
je suis curieux de savoir pourquoi vous voulez faire une telle chose. Les Chances sont, vous devriez laisser la collecte des ordures faire son travail. En python, la collecte des ordures est assez déterministe. Donc, vous n'avez pas vraiment à vous soucier autant de laisser des objets en mémoire comme vous le feriez dans d'autres langues (sans dire que le refcounting n'a pas d'inconvénients).
bien qu'une chose que vous devriez considérer est un enveloppement autour de n'importe quels objets ou ressources vous pouvez vous en débarrasser plus tard.
class foo(object):
def __init__(self):
self.some_big_object = some_resource
def killBigObject(self):
del some_big_object
en réponse à Addendum :
malheureusement, je ne crois pas qu'il y ait un moyen de faire ce que vous voulez faire comme vous voulez le faire. Voici une façon que vous pourriez vouloir considérer:
>>> class manager(object):
... def __init__(self):
... self.lookup = {}
... def addItem(self, name, item):
... self.lookup[name] = item
... item.setLookup(self.lookup)
>>> class Item(object):
... def __init__(self, name):
... self.name = name
... def setLookup(self, lookup):
... self.lookup = lookup
... def deleteSelf(self):
... del self.lookup[self.name]
>>> man = manager()
>>> item = Item("foo")
>>> man.addItem("foo", item)
>>> man.lookup
{'foo': <__main__.Item object at 0x81b50>}
>>> item.deleteSelf()
>>> man.lookup
{}
C'est un peu bordélique, mais ça devrait vous donner l'idée. Essentiellement, Je ne pense pas que lier l'existence d'un élément dans le jeu à si oui ou non affectés dans la mémoire est une bonne idée. C'est parce que les conditions de l'élément à ordures collectées sont probablement va être différent de ce que les conditions sont à l'élément dans le jeu. De cette façon, vous n'avez pas à trop s'inquiéter de cela.
ce que vous pourriez faire est de prendre le nom avec vous dans la classe et de faire une dictionairy:
class A:
def __init__(self, name):
self.name=name
def kill(self)
del dict[self.name]
dict={}
dict["a"]=A("a")
dict["a"].kill()