On Ctrl-d, call Close() like with file objects happen
Question: I've [wrote a
class](https://github.com/srgblnch/scpi/blob/master/scpi/scpi.py) that
inherits from _object_ and has instances of sub-objects that uses some
_threads_ for tasks. There are two socket _listeners_ that creates other
threads for each _accept_ ed connection. They do what they have to do. To
finish them, they are looking on a _Threading.Event_ object to know that they
have to finish.

I've noticed that, when exit the python console they are not notified (or
don't catch the notification) and the exit don't return control to the bash
console, unless a _Close()_ is called before.

First idea to fix it has been to implement the _'__del__'_ method to use the
garbage collector to clean it when exit.

    
    
    class ServiceProvider(object):
        def __init__(self):
            super(ServiceProvider,self).__init__()
            #...
            self.Open()
        def Open(self):
            #... Some threads are created.
        def Close(self):
            #.... Threading.Event to report the threads to finish
        def __del__(self):
            self.Close()
    

But the behaviour is the same. If I place a print in those methods, non in
_'__del__'_ , neither in _'Close'_ they are written. Unless it is closed
before, then the print in the _del_ is wrote.

Then I've implemented the _'__enter__'_ and _'__exit__'_ methods to manage the
_with_ statement. And the _exit_ behaves as expected and when the _with_ ends,
things are release. But what I really want is to have something like the _file
descriptors_ that event if _file.close()_ is not called, it is executed when
exits the program.

    
    
    class ServiceProvider(object):
        #...
        def __enter__(self):
            return self
        def __exit__(self):
            self.Close()
    

Searching for more solutions I've tried with
[atexit](https://docs.python.org/2/library/atexit.html) but not. I have
similar results that doesn't fix the issue. Even I collect all the objects
created of this class, the _doOnExit_ only writes its print if the objects in
the list are already _Close_.

    
    
    import atexit
    global objects2Close
    objects2Close = []
    
    @atexit.register
    def doOnExit():
        for obj in objects2Close:
            obj.Close()
    
    class ServiceProvider(object):
        def __init__(self):
            super(ServiceProvider,self).__init__()
            objects2Close.append(self)
    


Answer: It's usually a good idea to use `with` when you have resources that you don't
want to leak (files, connections, whatever else you care about).

Somewhere, just outside your main loop you should have something like:

    
    
    with ServiceProvider(some_params) as service_provider:
      rest_of_the_code()
    

What this does is that regardless of how you exit rest_of_the_code() (except
for kill -9) it will call service_provider.Close() at the end. This works for
exceptions and interrupts as well. Kill -9 doesn't work because the process is
kill at os level and doesn't have a chance to attempt to recover.

