【问题标题】:Python: how to "kill" a class instance/object with several referencesPython:如何“杀死”具有多个引用的类实例/对象
【发布时间】:2022-11-02 02:18:27
【问题描述】:

我需要删除/杀死一个类的实例,但它可能在其他一些类的变量中有引用。谁知道我怎样才能让它变得容易?

is_instance_exist = True

def check_vars():
    try:
        print('var1:' + str(var1))
    except:
        print('No var1')
    try:
        print('var2:' + str(var2))
    except:
        print('No var2')

def instance_deleted():
    global is_instance_exist
    is_instance_exist = False

def check_instance():
    global is_instance_exist
    print("Is instance exist: " + str(is_instance_exist))

class TestClass:
    def __init__(self, inn):
        self.tt = inn

    def __str__(self):
        return self.tt

    def change(self, inn):
        self.tt = inn

    def __del__(self):
        instance_deleted()

# ---------------------------------------
print("---1--- Create instance of class")
var1 = TestClass('5')
var2 = var1
check_vars()
check_instance()
# ---------------------------------------
print("---2--- Instance connectivity check")
var1.change('6')
check_vars()
check_instance()
# ---------------------------------------------------
print("---2--- Deleting var1")
del var1
check_vars()
check_instance()
# ---------------------------------------------------
print("---3--- Deleting var2")
del var2
check_vars()
check_instance()
# ---------------------------------------------------
print("---The end---")

删除每个变量是非常困难的。 有谁知道我怎么能轻松做到这一点?

.....................................

【问题讨论】:

    标签: python-3.x class


    【解决方案1】:

    如果有对该实例的引用,则无法删除该实例。 Python 使用垃圾收集器,因此如果仍在使用中,则无法释放内存。

    如果您想在代码中的多个位置访问一个实例,并且仍然能够从一个位置删除该实例,您可以将您的实例包装在一个对象/数组/字典中,并且只引用包装器。这样,只有您的包装器具有引用,您可以删除该引用。

    memory = {}
    memory["var1"] = 1
    memory["var2"] = 2
    memory2 = memory
    print(memory["var1"])
    print(memory["var2"])
    
    del memory["var1"]
    try:
        print(memory["var1"])
    except:
        print('var1 deleted')
    
    # we can delete from the other reference and it is deleted from both
    del memory2["var2"]
    try:
        print(memory["var2"])
    except:
        print('var2 deleted')
    

    更新就像 jsbueno https://stackoverflow.com/a/74268773/20351074 的回答中提到的那样,可以使用弱引用代替普通/强引用,其中弱引用不会增加引用计数,也不会阻止垃圾收集的发生。

    https://docs.python.org/3/library/weakref.html

    然而,在对象被实际销毁之前,即使没有强引用,弱引用也可能会返回该对象。

    【讨论】:

    • 优雅的解决方案))但不完全是我想要的
    • 您的回答总体上可以作为“这样做的方式”-只是碰巧该语言具有OP要求的功能-作为对弱引用的支持而实现。
    • @jsbueno 从那时起。我将其视为具有强引用的情况,似乎没有办法以这种方式删除它们而不包装它以防止增加计数。使用weakref 确实会带来更多收益,因为我不知道它们。
    【解决方案2】:

    虽然可以通过使用 Python 内省工具来做到这一点,但通常不会这样做。

    这样做常规的可以通过使用gc stdlib 模块中的垃圾收集器接口来实现引用:它允许您找到对对象的所有引用,然后您可以将对对象的每个引用设置为None - 这不会直截了当,艰难:有些地方你必须设置一个属性,其他地方的 rerence 将在映射键或映射值中,有时它会是序列的成员 - 但最重要的是,所有此实例的“用户”必须“意识到”它可能随时变为“无”,并且不要依赖该元素始终是您的类的实例。

    这导致我们实际的模式 Python 必须处理这个问题:弱引用。

    弱引用完全符合您的要求:它们只是与原始对象一起“消失”。唯一的缺点是,在任何使用它的地方都必须使与之兼容的用途消失。

    幸运的是,stdlib 'weakref' 模块本身带来了一些可能性:代理、集合和映射。然后,您必须小心将“消失”对象的弱引用传递给所有将使用它的地方,并且只在代码想要的地方保留一个强引用(即普通引用)杀死然后有控制权。

    您应该查看https://docs.python.org/3/library/weakref.html 的文档

    签入此示例代码,因为实例从 WeakSet 引用中“消失”,因为它们已从 real_instances 列表中删除,该列表保留了对它们的唯一非弱引用。

    
    
    from weakref import WeakSet
    
    class A:
        counter = 0
        def __init__(self):
            self.id = self.__class__.counter
            self.__class__.counter += 1
        def print(self):
            print(f"{self.id} is alive")
    
    
    real_instances = []
    weak_instances = WeakSet()
    
    def use_objects(mylist):
        for obj in mylist:
            obj.print()
    
    def main():
        for i in range(4):
            a = A()
            real_instances.append(a)
            weak_instances.add(a)
            del a
        while real_instances:
            use_objects(weak_instances)
            real_instances.pop()
    
    main()
    

    【讨论】:

      猜你喜欢
      • 2013-05-17
      • 1970-01-01
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      相关资源
      最近更新 更多