Warum funktioniert das nicht? Ich versuche, eine Instanz einer Klasse selbst zu löschen.
>>> class A():
def kill(self):
del self
>>> a = A()
>>> a.kill()
>>> a
<__main__.A instance at 0x01F23170>
"Selbst" ist nur ein Verweis auf das Objekt. 'del self' löscht statt des eigentlichen Objekts den 'self'-Verweis aus dem lokalen Namespace der Funktion kill.
Sehen Sie sich an, was passiert, wenn diese beiden Funktionen ausgeführt werden:
>>> 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
Sie müssen del nicht zum Löschen von Instanzen verwenden. Sobald der letzte Verweis auf ein Objekt verschwunden ist, wird das Objekt Müll gesammelt. Vielleicht sollten Sie uns mehr über das gesamte Problem erzählen.
In diesem speziellen Kontext ist Ihr Beispiel nicht sehr sinnvoll.
Wenn ein Wesen einen Gegenstand aufnimmt, behält der Gegenstand eine individuelle Existenz bei. Es verschwindet nicht, weil es abgeholt wurde. Es existiert immer noch, aber es befindet sich (a) am selben Ort wie das Sein und (b) kann nicht mehr abgeholt werden. Während es einen Statuswechsel hatte, existiert es immer noch.
Es gibt eine wechselseitige Verbindung zwischen Sein und Gegenstand. Das Wesen hat den Gegenstand in einer Sammlung. Der Gegenstand ist mit einem Wesen verbunden.
Wenn ein Gegenstand von einem Wesen aufgegriffen wird, müssen zwei Dinge passieren.
Das Wesen fügt das Element in einer set
von Elementen hinzu. Ihr bag
-Attribut könnte beispielsweise eine solche set
sein. [Eine list
ist eine schlechte Wahl - ist die Reihenfolge in der Tasche wichtig?]
Der Ort des Gegenstands ändert sich von dem Ort, an dem er sich befand, zum Ort des Wesens. Es gibt wahrscheinlich zwei Klassen os Items - diejenigen mit einem unabhängigen Ortsgefühl (weil sie sich alleine bewegen) und Items, die den Ort an das Sein oder den Ort delegieren müssen, an dem sie sitzen.
Unter keinen Umständen muss ein Python-Objekt jemals gelöscht werden. Wenn ein Gegenstand "zerstört" wird, ist er nicht in der Tasche eines Wesens. Es ist nicht an einem Ort.
player.bag.remove(cat)
Ist alles, was benötigt wird, um die Katze aus der Tasche zu lassen. Da die Katze nirgendwo anders verwendet wird, existiert sie sowohl als "benutzter" Speicher als auch als nicht vorhanden, da nichts in Ihrem Programm darauf zugreifen kann. Es verschwindet leise aus dem Speicher, wenn ein Quantenereignis eintritt und Speicherreferenzen gesammelt werden.
Auf der anderen Seite,
here.add( cat )
player.bag.remove(cat)
Bringt die Katze an den aktuellen Ort. Die Katze existiert weiterhin und wird nicht mit dem Müll ausgelöscht.
Ich glaube ich habe es endlich geschafft!
HINWEIS: Sie sollten dies nicht in normalem Code verwenden , aber es ist possible . Dies ist nur als Kuriosität gedacht.
# 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
Wenn das Objekt in der __new__
-Methode erstellt wird, wird die Instanz durch einen schwachen Referenz-Proxy ersetzt, und im _alive-Klassenattribut wird nur eine starke Referenz beibehalten.
Schwachreferenz ist eine Referenz, die nicht als Referenz gilt, wenn der Garbage Collector das Objekt erfasst. Betrachten Sie dieses Beispiel:
>>> 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
Der einzige starke Verweis auf die Instanz wird also im _alive-Klassenattribut gespeichert. Wenn die Methode commit_suicide () die Referenz entfernt, wird die Instanz garbage-gesammelt.
Realistisch gesehen sollten Sie das Objekt nicht löschen müssen, um das zu tun, was Sie versuchen. Stattdessen können Sie den Status des Objekts ändern. Ein Beispiel dafür, wie dies funktioniert, ohne in die Kodierung einzusteigen, wäre, wenn Ihr Spieler gegen ein Monster kämpft und das Monster tötet. Der Zustand dieses Monsters kämpft. Das Monster greift auf alle für den Kampf erforderlichen Methoden zu. Wenn das Monster stirbt, weil seine Gesundheit auf 0 sinkt, ändert sich der Status des Monsters in tot und Ihr Charakter stoppt automatisch den Angriff. Diese Methodik ist der Verwendung von Flags oder sogar Schlüsselwörtern sehr ähnlich.
Außerdem ist das Löschen von Klassen anscheinend nicht erforderlich, da sie automatisch Müll gesammelt werden, wenn sie nicht mehr verwendet werden.
Ich versuche dasselbe. Ich habe ein RPG-Kampfsystem, in dem meine Death- (Selbst-) Funktion das eigene Objekt der Fighter-Klasse töten muss. Aber es schien, dass es nicht möglich ist. Vielleicht sollte mein Klassenspiel, in dem ich alle Teilnehmer sammle, Einheiten aus der "fiktionalen" Karte löschen ???
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()
Ich kann Ihnen nicht sagen, wie dies mit Klassen möglich ist, aber Funktionen können sich selbst löschen.
def kill_self(exit_msg = 'killed'):
global kill_self
del kill_self
return exit_msg
Und sehen Sie die Ausgabe:
>>> 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
Ich denke nicht, dass es möglich ist, eine einzelne Instanz einer Klasse zu löschen, ohne deren Namen zu kennen.
HINWEIS: Wenn Sie der Funktion einen anderen Namen zuweisen, verweist der andere Name zwar auf den alten, führt jedoch zu Fehlern, sobald Sie versuchen, ihn auszuführen:
>>> 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
Wenn Sie einen einzelnen Verweis auf das Objekt verwenden, kann das Objekt sich selbst töten, indem Sie den externen Verweis auf sich selbst zurücksetzen.
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()
Sie können die Logiksteuerung natürlich auch durchführen, indem Sie die Objektexistenz von außerhalb des Objekts (anstatt des Objektzustands) prüfen, z. B. in:
if object_exists:
use_existing_obj()
else:
obj = Obj()
Tatsächlich führt Python eine Müllsammlung durch Referenzzählung durch. Sobald der letzte Verweis auf ein Objekt außerhalb des Gültigkeitsbereichs liegt, wird es gelöscht. In deinem Beispiel:
a = A()
a.kill()
Ich glaube nicht, dass es eine Möglichkeit gibt, dass sich die Variable 'a' implizit auf Keine setzt.
Ich bin neugierig, warum Sie so etwas tun wollen. Die Chancen stehen gut, dass Sie die Müllsammlung einfach erledigen lassen sollten. In Python ist die Garbage Collection ziemlich deterministisch. Sie müssen sich also nicht so sehr darum kümmern, dass Objekte wie in anderen Sprachen im Gedächtnis bleiben (nicht zu sagen, dass das Nachzählen keine Nachteile hat).
Eine Sache, die Sie in Betracht ziehen sollten, ist das Einwickeln von Objekten oder Ressourcen, die Sie später entfernen können.
class foo(object):
def __init__(self):
self.some_big_object = some_resource
def killBigObject(self):
del some_big_object
In Reaktion auf Nulls Nachtrag :
Leider glaube ich nicht, dass es eine Möglichkeit gibt, das zu tun, was Sie wollen, wie Sie es möchten. Hier ist eine Möglichkeit, die Sie berücksichtigen möchten:
>>> 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
{}
Es ist ein bisschen chaotisch, aber das sollte Ihnen die Idee geben. Im Grunde glaube ich nicht, dass es eine gute Idee ist, die Existenz eines Gegenstandes im Spiel daran zu binden, ob er im Speicher zugewiesen ist oder nicht. Dies ist darauf zurückzuführen, dass sich die Bedingungen für das Sammeln von Müll wahrscheinlich von den Bedingungen für den Gegenstand im Spiel unterscheiden. Auf diese Weise müssen Sie sich nicht so viele Sorgen machen.
class A:
def __init__(self, function):
self.function = function
def kill(self):
self.function(self)
def delete(object): #We are no longer in A object
del object
a = A(delete)
print(a)
a.kill()
print(a)
Kann dieser Code funktionieren?
sie könnten den Namen in der Klasse mitnehmen und eine Aussprache machen:
class A:
def __init__(self, name):
self.name=name
def kill(self)
del dict[self.name]
dict={}
dict["a"]=A("a")
dict["a"].kill()
Dies ist etwas, das ich in der Vergangenheit gemacht habe. Erstellen Sie eine Liste von Objekten, und Sie können Objekte dann mit der list.remove()
-Methode selbst löschen lassen.
bullet_list = []
class Bullet:
def kill_self(self):
bullet_list.remove(self)
bullet_list += [Bullet()]