84

为什么这行不通?我正在尝试使类的实例自行删除。

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


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

14 回答 14

73

'self' 只是对对象的引用。'del self' 正在从 kill 函数的本地命名空间中删除 'self' 引用,而不是实际的对象。

要亲自了解这一点,请查看执行这两​​个函数时会发生什么:

>>> 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
于 2008-11-16T03:41:12.777 回答
47

您不需要首先使用 del 删除实例。一旦对对象的最后一个引用消失,该对象将被垃圾回收。也许你应该告诉我们更多关于完整问题的信息。

于 2008-11-16T03:46:09.163 回答
36

我想我终于明白了!
注意:您不应该在普通代码中使用它,但它是可能的。这只是出于好奇,请参阅其他答案以了解此问题的实际解决方案。


看看这段代码:

# 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

__new__方法中创建对象时,实例被弱引用代理替换,唯一的强引用保存在 _alive 类属性中。

什么是弱引用?

弱引用是垃圾收集器收集对象时不计为引用的引用。考虑这个例子:

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

所以对实例的唯一强引用存储在 _alive 类属性中。当 commit_suicide() 方法删除引用时,实例被垃圾收集。

于 2016-08-13T11:55:25.913 回答
14

在这种特定情况下,您的示例没有多大意义。

当一个存有捡起一个物品时,该物品保留了一个单独的存在。它不会因为被捡起而消失。它仍然存在,但它 (a) 与存在在同一位置,并且 (b) 不再有资格被拾取。虽然它的状态发生了变化,但它仍然存在。

存在和项目之间存在双向关联。The Being 在一个集合中拥有该项目。该项目与一个存在相关联。

当一个物品被一个存在捡起时,必须发生两件事。

  • 存在如何在某些项目中添加set项目。bag例如,您的属性可能是这样的set. [Alist是一个糟糕的选择——订单在袋子里重要吗?]

  • 物品的位置从它以前的位置变为存在的位置。可能有两类 os 项目 - 具有独立位置感的项目(因为它们自己移动)和必须将位置委托给他们所在的存在或地方的项目。

在任何情况下都不需要删除任何 Python 对象。如果一个项目被“摧毁”,那么它就不是在一个存在的包里。它不在一个位置。

player.bag.remove(cat)

只需要让猫从袋子里出来。由于 cat 没有在其他任何地方使用,它既作为“已用”内存存在,又不存在,因为您的程序中没有任何东西可以访问它。当一些量子事件发生并且内存引用被垃圾收集时,它会悄悄地从内存中消失。

另一方面,

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

将猫放在当前位置。猫继续存在,不会和垃圾一起被淘汰。

于 2008-11-16T14:26:51.353 回答
7

实际上,您不需要删除对象来执行您正在尝试执行的操作。相反,您可以更改对象的状态。一个不进入编码的情况下如何工作的例子是你的玩家与怪物战斗并杀死怪物。这个怪物的状态是战斗。怪物将访问战斗所需的所有方法。当怪物因为生命值降到0而死亡时,怪物状态会变为死亡,你的角色会自动停止攻击。这种方法与使用标志甚至关键字非常相似。

同样显然在 python 中删除类是不需要的,因为当它们不再使用时它们将被自动收集。

于 2012-09-28T05:41:34.537 回答
3

I am trying the same thing. I have a RPG battle system in which my Death(self) function has to kill the own object of the Fighter class. But it appeared it`s not possible. Maybe my class Game in which I collect all participants in the combat should delete units form the "fictional" map???

   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()
于 2011-12-08T10:58:14.260 回答
3

我无法告诉您如何使用类来实现这一点,但函数可以自行删除。

def kill_self(exit_msg = 'killed'):
    global kill_self
    del kill_self
    return exit_msg

并查看输出:

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

我认为在不知道类名的情况下删除类的单个实例是不可能的。

注意: 如果您为函数分配另一个名称,则另一个名称仍将引用旧名称,但一旦您尝试运行它就会导致错误:

>>> 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
于 2010-08-08T17:33:22.300 回答
2

事实上,Python 通过引用计数来进行垃圾收集。一旦对对象的最后一个引用超出范围,它就会被删除。在您的示例中:

a = A()
a.kill()

我不相信变量“a”有任何方法可以将自己隐式设置为无。

于 2008-11-16T03:59:10.463 回答
1

如果您使用对对象的单个引用,则对象可以通过重置对自身的外部引用来杀死自己,如下所示:

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

您当然可以通过从对象外部(而不是对象状态)检查对象是否存在来进行逻辑控制,例如:

if object_exists:
   use_existing_obj()
else: 
   obj = Obj()
于 2013-02-01T11:27:57.583 回答
1

这是我过去做过的事情。创建一个对象列表,然后您可以使用该list.remove()方法让对象自行删除。

bullet_list = []

class Bullet:
    def kill_self(self):
        bullet_list.remove(self)

bullet_list += [Bullet()]
于 2018-11-18T00:08:52.497 回答
0

我很好奇你为什么要做这样的事情。很有可能,你应该让垃圾收集来完成它的工作。在 python 中,垃圾收集是相当确定的。因此,您不必像在其他语言中那样担心将对象留在内存中(并不是说引用计数没有缺点)。

尽管您应该考虑的一件事是包装您以后可能会摆脱的任何对象或资源。

class foo(object):
    def __init__(self):
        self.some_big_object = some_resource

    def killBigObject(self):
        del some_big_object

回应Null 的附录

不幸的是,我不相信有一种方法可以按照您想做的方式做您想做的事情。这是您可能希望考虑的一种方法:

>>> 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
 {}

这有点混乱,但这应该给你的想法。从本质上讲,我不认为将游戏中某个项目的存在与它是否在内存中分配联系起来是一个好主意。这是因为物品被垃圾回收的条件可能与游戏中物品的条件不同。这样,您就不必为此担心太多。

于 2008-11-16T04:19:45.307 回答
0

你能做的就是在课堂上带上你的名字并制作字典:

class A:
  def __init__(self, name):
    self.name=name
  def kill(self)
    del dict[self.name]

dict={}
dict["a"]=A("a")
dict["a"].kill()
于 2015-03-25T11:36:00.023 回答
0
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)

这段代码可以工作吗?

于 2018-10-29T19:52:19.527 回答
0

替换工具:

class A:

    def __init__(self):
        self.a = 123

    def kill(self):
        from itertools import chain
        for attr_name in chain(dir(self.__class__), dir(self)):
            if attr_name.startswith('__'):
                continue
            attr = getattr(self, attr_name)
            if callable(attr):
                setattr(self, attr_name, lambda *args, **kwargs: print('NoneType'))
            else:
                setattr(self, attr_name, None)
        a.__str__ = lambda: ''
        a.__repr__ = lambda: ''
a = A()
print(a.a)
a.kill()

print(a.a)
a.kill()

a = A()
print(a.a)

将输出:

123
None
NoneType
123
于 2020-07-28T11:35:21.877 回答