Home > Mobile >  Python: how to "kill" a class instance/object with several references
Python: how to "kill" a class instance/object with several references

Time:11-01

I need to delete/kill an instance of a class, but it may have references in variables in some other classes. Who knows how I can make it easy?

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

Removing every variable is very difficult. Does anyone know how I can do this easily?

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

CodePudding user response:

There is no way to delete an instance if there is a reference to that instance. Python uses a garbage collector, so no way to release the memory if still in use.

If you want to access a instance in multiple places in your code, and still be able to delete the instance from one place, you can wrap your instance in a object/array/dict and only ever reference the wrapper. This way only your wrapper has a reference and you can delete that reference.

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

CodePudding user response:

While it would be possible to do that, through the use of Python introspection tools, that is not normally done.

Doing that with regular references would be poossible by using the garbage collector interface in the gc stdlib module: that allows you to find all references to your object, and then you could go about setting every reference to your object to None - that would not be straightforward, tough: there are places were you'd have to set an attribute, other places where the rerence would be in a map key, or a map value, and sometimes it would be the member of a sequence - but most importantly, all the "users" of this instance must be "aware" that it might become a "None" at any time, and do not rely on that element always being an instance of your class.

Which leads us to the actual pattern Python has to deal with that: weakreferences.

Weakreferences do exactly what you want: they simply "vanish" along with the original object. The only drawback is that everywhere it is used have to make a use compatible with it vanishing.

Fortunately, the stdlib 'weakref' module itself brings some possibilities: proxies,sets and mappings. And then, you have to be careful to just pass weak-references of your "vanishing" object to all places that will use it, and only keep a single strong reference (i.e. a normal reference), in a place the code that wants to kill then have control.

You should check the docs at https://docs.python.org/3/library/weakref.html

Check in this sample code as the instances "vanish" from the WeakSet refences as they are deleted from the real_instances list which keeps the sole non-weak references to them.



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