-1

Say we have a class Test which has a static method as so:

import weakref
class Test:
    @staticmethod
    def hello():
        return 'Hello'

We create an instance of Test - call its method, we also create a weak reference to the instance as well. Then delete the variable and see if we can call the method again:

test_ins = Test()
test_ins_weakref = weakref.ref(test_ins)

print(test_ins.hello())
print("---deleting test_ins---")
del test_ins
print(test_ins_weakref().hello())

Before we delete the instance, it works (as it should) - but then it doesn't (Checking the type yields NoneType and it of course does not have a method called hello).
If we don't perform the del operation on the instance, we would get <class '__main__.Test'> and thus we can call the method.

Now lets try deleting the class itself:

test_ins = Test()
test_ins_weakref = weakref.ref(test_ins)

print(test_ins.hello())
print("---deleting test_ins---")
del Test
print(test_ins_weakref().hello())

It works.


My main question is if someone can explain what is happening here, because when I read the code I don't understand how and why it works that way.

Deleting a whole class doesn't mean that now all its instances point to nothing? Because, after deleting the class Test we cannot access the method nor create new instances..

new_ins = Test()
print(Test().hello())

Both yield

NameError: name 'Test' is not defined

However we can tweak things "around" and use the working instance type to create a new one:

new_ins = type(test_ins)()
print(new_ins.hello())

Works just fine.

CodeCop
  • 1
  • 2
  • 15
  • 37

1 Answers1

1

From the docs:

when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else.

That's why in this block:

test_ins = Test()
test_ins_weakref = weakref.ref(test_ins)

print(test_ins.hello())
print("---deleting test_ins---")
del test_ins
print(test_ins_weakref().hello())

the last line produces an error (the object to which test_ins_weakref references was destroyed by garbage collector).

In this block:

test_ins = Test()
test_ins_weakref = weakref.ref(test_ins)

print(test_ins.hello())
print("---deleting test_ins---")
del Test
print(test_ins_weakref().hello())

You delete Test but the class of the test_ins is still in the memory. It wasn't collected because it has a strong reference to it.

It can be seen here:
import weakref
class Test:
    @staticmethod
    def hello():
        return 'Hello'

test_ins = Test()
print(f"{id(Test)=}")
del Test
print(f"{id(test_ins.__class__)=}")

It will give the same id because the objects is still alive. So when you do del Test you are not deleting the object from the memory, you are removing the variable Test that was referencing the object. If there is at least one strong reference to that object, it won't be deleted from the memory.

That's why this block:

new_ins = type(test_ins)()
print(new_ins.hello())

works.

marke
  • 1,024
  • 7
  • 20