The way threading.Thread (and therefore threading.Timer ) is that each thread is registered with the threading module, and after the interpreter exits, the interpreter will wait until all registered threads are completed before the interpreter itself completes. This is done so that the threads actually finish execution, instead of the interpreter being brutally removed from under them. Therefore, when you press ^ C, the main thread receives a signal, decides to end, and waits for the timer to end.
You can set daemonic streams (using the setDaemon method) so that the streaming module does not wait for these streams, but if they execute Python code when the interpreter exits, you get confused errors when exiting. Even if you cancel threading.Timer (and set it with a daemon), it can still wake up during the destruction of the interpreter, because the threading.Timer cancel method simply tells threading.Timer do nothing when it wakes up, but it should actually execute the code Python to make this determination.
There is no elegant way to terminate threads (other than the current one) and a reliable way to terminate a thread that is blocked. A more manageable approach to timers is usually an event loop, such as graphical interfaces and other event-driven systems. What to use depends entirely on what else your program will do.
source share