At this code, an object of Foo()
class is still alive after creating new one. I guess that reason is in the circular references on appending object's list property. So, how to let garbage collector free old object, withot manual calling gc.collect()
?
import gc
class Foo():
def __init__(self):
self.functions = []
print('CREATE', self)
def some_func(self):
for i in range(3):
self.functions.append(self.print_func)
print(self.functions)
def print_func(self):
print('I\'m a test')
def __del__(self):
print('DELETE', self)
foo = Foo()
foo.some_func()
foo = Foo()
# gc.collect()
input = input()
input()
at the end is just for keeping program running. Real project with this problem contains while loop, so keeping old unused objects may cause a memory leak.
Now, output:
CREATE <__main__.Foo object at 0x000002747001D850>
[<bound method Foo.print_func of <__main__.Foo object at 0x000002747001D850>>, <bound method Foo.print_func of <__main__.Foo object at 0x000002747001D850>>, <bound method Foo.print_func of <__main__.Foo object at 0x000002747001D850>>]
CREATE <__main__.Foo object at 0x000002746FD0BB90>
Output with calling gc.collect()
:
CREATE <__main__.Foo object at 0x0000021E45F0D8E0>
[<bound method Foo.print_func of <__main__.Foo object at 0x0000021E45F0D8E0>>, <bound method Foo.print_func of <__main__.Foo object at 0x0000021E45F0D8E0>>, <bound method Foo.print_func of <__main__.Foo object at 0x0000021E45F0D8E0>>]
CREATE <__main__.Foo object at 0x0000021E45CDBB90>
DELETE <__main__.Foo object at 0x0000021E45F0D8E0>
It's a result, that I want to get, but without using gc
You can use weakref.WeakMethod
to avoid creating strong references to the self.print_func
method in the list attribute.
Note that to call a weakly referenced method you would have to dereference it first by calling the weakref before calling the actual method:
from weakref import WeakMethod
class Foo():
def __init__(self):
self.functions = []
print('CREATE', self)
def some_func(self):
for i in range(3):
self.functions.append(WeakMethod(self.print_func))
print(self.functions)
def print_func(self):
print('I\'m a test')
def __del__(self):
print('DELETE', self)
foo = Foo()
foo.some_func()
foo.functions[0]()()
foo = Foo()
input()
This outputs:
CREATE <__main__.Foo object at 0x0000018F0B397150>
[<weakref at 0x0000018F0B18E0A0; to 'Foo' at 0x0000018F0B397150>, <weakref at 0x0000018F0B18E1F0; to 'Foo' at 0x0000018F0B397150>, <weakref at 0x0000018F0B18E490; to 'Foo' at 0x0000018F0B397150>]
I'm a test
CREATE <__main__.Foo object at 0x0000018F0B397190>
DELETE <__main__.Foo object at 0x0000018F0B397150>
Demo: https://replit.com/@blhsing1/LightheartedTurquoiseChord