1

I try to use the context manager to have all the clean up code in the finally: part of my fonction.

  • One goal of the clean up is to make sure that all references to the class initialize_stuff() are set to None.
  • using the code below, there is still an active reference to the initialize_stuff() at the end
  • I can "force" the variable to None, but I may forget it when I use the context manager, I expect the context manager to do it.

Is it possible? How?

Notes:

import contextlib
import gc

class initialize_stuff(object):
    def use(self):
        pass

@contextlib.contextmanager
def do_things():
    try:
        release_me = initialize_stuff()
        yield release_me 
    
    finally:
        release_me = None
        gc.collect()


with do_things() as release_me:
    release_me.use()
    # release_me = None
    
if release_me is not None:
    print("release_me is not released")
else:
    print("yeah")

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Nico
  • 17
  • 5
  • 1
    I'd recommend reading https://nedbatchelder.com/text/names.html – jonrsharpe Jan 12 '23 at 09:44
  • I understand why there is still a reference to initialize_stuff(), but i'm not sure how to make a "cleaner" version where the `finally:` part does the clean up – Nico Jan 12 '23 at 10:15
  • Short of returning a [`weakref`](https://docs.python.org/3/library/weakref.html), so the reference held by `release_me` isn't included in the underlying object's reference count, you can't. – jonrsharpe Jan 12 '23 at 10:20

1 Answers1

-1

I found an answer, not sure if it's a "clean" one: I use an object in-between the call and the target class. This way, only the object in-between keep the "real" reference and it can be set to None in the context manager.

Added: send_to_class

import contextlib
import gc


class send_to_class(object):
    def __init__(self, item):
        self.item = item
    
    def __getattr__(self, attr): # récupère les appels sur des méthodes non connues
        return getattr(self.item, attr)

class initialize_stuff(object):
    def use(self):
        pass

@contextlib.contextmanager
def do_things():
    try:
        release_me = send_to_class(initialize_stuff())
        yield release_me 
    
    finally:
        release_me.item = None
        gc.collect()


with do_things() as release_me:
    release_me.use()
    
if release_me is not None:
    print("release_me is not released")
else:
    print("yeah")

Nico
  • 17
  • 5