Avoid calling an object after it is dead
Question: I have a `threading.Thread` subclass in python and its run method is as
follows:

    
    
    def run(self):
        while self.caller.isAlive():
            details = self.somefile.read()
            if self.status() and details:
                self.handler(details)
            time.sleep(self.interval)
    

The arguments passed to this thread's `__init__` are as follows:

  * `caller` is the thread object of the caller
  * `status` is the callable that returns a boolean indicating the status
  * `handler` is called to handle the details (some data)

The while loop checks if the caller thread is alive. If yes, it enters the
loop and checks if it's time for a status update and handles the data. It
sleeps and continues the loop. Note that in this case the `caller` is main
thread and `status` is provided by the main thread (a function of some sort).

**The issue is** in between `while self.caller.isAlive():` and `if
self.status() and details:`. If the caller thread gets terminated in that tiny
fraction of a second, its `status` function would still get called and it will
raise an error. Are there any ways to prevent this?

**Edit:** The main thread invokes this thread. The main thread has the status
function inside a class. Since it is a classmethod, the instance parameter
`self` must be passed while calling it. In my case, it is like:

    
    
    def OnStatus(self, *args, **kwargs):
        ...
    

When the main thread is exited (normally) the class object and it's instances
are destroyed, but the thread that was started still persists and might call:

    
    
    # self.status is self.OnStatus() defined before,
    # it is passed as the status callable to init
    self.status() # Things might go wrong here (at the wrong time)
    

**Edit** Tried this with a wxpython application and there was an exception
raised!

    
    
    'The object that you are referring to is:'
    <bound method TextCtrl.IsShown of wxPython wrapper for DELETED TextCtrl object! (The C++ object no longer exists.)>
    
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
        self.run()
      File "/home/user/Desktop/test.py", line 37, in run
        if self.status() and details:
      File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 9179, in IsShown
        return _core_.Window_IsShown(*args, **kwargs)
    TypeError: in method 'Window_IsShown', expected argument 1 of type 'wxWindow const *'
    


Answer: Nothing is stopping you from calling `status()` on the caller after the main
thread has ended. The `caller` object will still be there. It stays alive
because your background thread still holds a reference to it, which means its
reference count is still non-zero. Consider this example:

    
    
    import threading
    import time
    
    class Ok(threading.Thread):
        def __init__(self, obj):
            super(Ok, self).__init__()
            self.obj = obj
    
        def run(self):
            while True:
                print self.obj.ok
                time.sleep(2)
    
    class Obj(object):
        def __init__(self):
            self.ok = "hey"
    
    
    o = Obj()
    t = Ok(o)
    t.start()
    del o
    

We create an instance of `Obj` in the main thread, and explicitly delete the
reference to it from the main thread just before it ends. However, our output
looks like this:

    
    
    hey
    hey
    hey
    hey
    hey
    hey
    <forever>
    

Because the background thread has a reference to the instance of `Obj`, it
stays alive even though the main thread is finished.

Additionally, I would recommend using an `Event` to signal that the `caller`
thread is shutting down, so that the background`Thread` will be woken up from
sleep as soon as it occurs:

    
    
    caller_dead = threading.Event()
    
    def run(self):
        while not caller_dead.is_set()
            details = self.somefile.read()
            if self.status() and details:
                self.handler(details)
            caller_dead.wait(self.interval)
    
    ....
    # This is the end of your main thread
    caller_dead.set()
    

