webentwicklung-frage-antwort-db.com.de

Python-Objekt löscht sich selbst

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>
56
Null

"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
66
Jeremy Ruten

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.

40
Ned Batchelder

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.

13
S.Lott

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.


Sehen Sie sich diesen Code an:

# 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.

Was ist eine schwache Referenz?

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.

8
les

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. 

4
Zachary Kraus

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()
3
Ilian Zapryanov

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
2

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()
1
Basel Shishani

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.

1
Cybis

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.

0
Jason Baker
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?

0
Anonyme

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

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()]
0
Henry