Python对象删除自身


75

为什么不起作用?我试图使一个类的实例本身删除。

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


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

14
您为什么首先要这样做?

5
@hop:一种情况可能是当删除所包含的对象时,弱引用“容器”将自身删除。
Noob Saibot 2014年

Answers:


70

“自我”只是对对象的引用。“ 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

11
有没有一种方法可以设计一种使实例自行删除或调用全局函数将其删除的方法?
2014年

45

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


有没有一种方法可以设计一种使实例自行删除或调用全局函数将其删除的方法?
2014年

3
@Zen在Python中无法删除实例。您所能做的就是删除对实例的引用,一旦所有引用消失,该对象将被回收。
Ned Batchelder 2014年

1
是否有删除所有这些参考的线索?
2014年

2
@Zen,您必须足够了解您的程序,才能知道指的是您的对象。为什么要删除对象?您为什么在乎,当它不再使用时,它会自行消失。
Ned Batchelder 2014年

27

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


看一下这段代码:

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


14

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

当众生拿起一个物品时,该物品会保留一个个体的存在。它不会消失,因为它已被捡起。它仍然存在,但(a)与存在者的位置相同,并且(b)不再有资格被拾取。状态更改后,它仍然存在。

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

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

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

  • 物品的位置从原来的位置更改为存在的位置。大概有两类os物品-具有独立位置感的物品(因为它们自己移动)和必须将位置委托给他们所坐的存在或位置的物品。

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

player.bag.remove(cat)

仅是让猫从书包中脱出所需要的。由于猫没有在其他任何地方使用,因此它们都将作为“已用”内存存在,并且不存在,因为程序中没有任何内容可以访问它。当发生一些量子事件并且内存引用被垃圾回收时,它将从内存中悄悄消失。

另一方面,

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

将猫放到当前位置。猫继续存在,不会与垃圾一起扔掉。


3
薛定inger的猫活着!还是没有!令人讨厌的《哥本哈根解释》令人困惑。所以是垃圾回收。
S.Lott

是否有意义 ?-是一个宗教问题,这是怎么回事?-是科学问题!
布劳尔

@Blauohr:因为我相信软件必须捕捉含义,所以我正在做出宗教判断。
S.Lott

@Blauohr:因为我看不到含义和发生的事情之间的有用区别,如果发生的事情不是它的意思,那么就有一个错误,我们需要使发生的事情与所意图的相符。对发生的情况进行深入分析(这是一个错误)并没有帮助。
S.Lott

5

实际上,您无需删除对象即可执行您想做的事情。相反,您可以更改对象的状态。在不进行编码的情况下如何工作的一个示例是您的玩家与怪物战斗并杀死怪物。这个怪物的状态正在战斗。怪物将使用战斗所需的所有方法。当怪物由于生命值降至0而死亡时,怪物状态将变为死亡,并且您的角色将自动停止攻击。这种方法非常类似于使用标志甚至关键字。

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


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

现在尝试通过从其他模块调用kill_self来尝试此操作。
丹尼尔·克鲁夫

3

我正在尝试同样的事情。我有一个RPG战斗系统,其中我的Death(self)函数必须杀死Fighter类自己的对象。但是看来这是不可能的。也许我收集所有参加战斗的班级游戏应该从“虚构”地图中删除单位???

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

2
该代码示例冗长,但从概念上讲,“从虚构图中删除”是解释从给定范围中删除引用的一种好方法。
Dave Rawks'3

2

确实,Python通过引用计数进行垃圾回收。一旦对对象的最后引用超出范围,则将其删除。在您的示例中:

a = A()
a.kill()

我不认为有任何方式可以将变量“ a”隐式设置为“无”。


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

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

有点混乱,但这应该可以给您这个想法。从本质上讲,我不认为将游戏中某个物品的存在与是否在内存中分配挂钩不是一个好主意。这是因为要垃圾收集的物品的条件可能与游戏中物品的条件不同。这样,您不必为此担心太多。


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

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)

此代码可以工作吗?


欢迎使用Stack Overflow!感谢您提供此代码段,它可能会提供一些有限的即时帮助。一个适当的解释,将大大提高其长期的价值通过展示为什么这是一个很好的解决了这个问题,并会使其与其他类似的问题,更有助于未来的读者。请编辑您的答案以添加一些解释,包括您所做的假设。
再见StackExchange,

0

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

bullet_list = []

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

bullet_list += [Bullet()]

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.