Python对象删除自身

时间:2008-11-16 03:30:00

标签: python memory-management instance

为什么这不起作用?我正在尝试将类的实例删除。

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


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

14 个答案:

答案 0 :(得分:66)

'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

答案 1 :(得分:40)

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

答案 2 :(得分:13)

在这个特定的背景下,你的例子没有多大意义。

当一个人拿起物品时,该物品保留个人存在。它并没有消失,因为它被拾起了。它仍然存在,但它(a)与存在位于同一位置,并且(b)不再有资格被接收。虽然状态发生了变化,但它仍然存在。

存在与物品之间存在双向关联。存在集合中的物品。该物品与存在相关联。

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

  • The Being如何在一些set个项目中添加项目。例如,您的bag属性可能是set。 [A list是一个糟糕的选择 - 在包里订购物品吗?]

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

在任何情况下都不需要删除任何Python对象。如果一件物品被“摧毁”,那么它就不在一个存在的包里。它不在某个地方。

player.bag.remove(cat)

是否需要让猫从包中取出。由于cat不会在其他任何地方使用,因此它将作为“已使用”的内存存在而不存在,因为程序中的任何内容都无法访问它。当一些量子事件发生并且内存引用被垃圾收集时,它将从内存中悄然消失。

另一方面,

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

将猫放在当前位置。猫继续存在,不会被垃圾熄灭。

答案 3 :(得分:10)

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

<小时/> 看看这段代码:

# 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()方法删除引用时,实例被垃圾收集。

答案 4 :(得分:4)

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

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

答案 5 :(得分: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

答案 6 :(得分:3)

我正在尝试同样的事情。我有一个RPG战斗系统,其中我的死亡(自我)功能必须杀死战斗机类的自己的对象。但它似乎不可能。也许我收集战斗中所有参与者的班级游戏应该从“虚构”地图中删除单位???

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

答案 7 :(得分:1)

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

a = A()
a.kill()

我不相信变量'a'有任何方法可以隐含地将自己设置为None。

答案 8 :(得分: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()

答案 9 :(得分:0)

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

虽然您应该考虑的一件事是围绕任何对象或资源的包装器,您可能会在以后摆脱它。

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

    def killBigObject(self):
        del some_big_object

回应Null's addendum

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

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

这有点乱,但这应该给你这个想法。从本质上讲,我不认为将一个项目在游戏中的存在与它在内存中的分配是一个好主意。这是因为物品被垃圾收集的条件可能与游戏中物品的条件不同。这样,你就不用太担心了。

答案 10 :(得分: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()

答案 11 :(得分: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)

此代码可以工作吗?

答案 12 :(得分:0)

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

bullet_list = []

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

bullet_list += [Bullet()]

答案 13 :(得分: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