The following code:
import threading
import time
from functools import partial
from itertools import count
def daemon_loop(sleep_interval, stop_event):
    for j in count():
        print(j)
        if stop_event.is_set():
            break
        time.sleep(sleep_interval)
        print('Slept %s' % sleep_interval)
    print('Prod terminating')
if __name__ == '__main__':
    stop_event = threading.Event() #https://stackoverflow.com/a/41139707/281545
    target = partial(daemon_loop, sleep_interval=2, stop_event=stop_event)
    prod_thread = threading.Thread(target=target,
                                   # daemon=True
                                   )
    try:
        prod_thread.start()
        while True:
            time.sleep(10)
    except KeyboardInterrupt:
        print('Terminating...')
        stop_event.set()
prints on a keyboard interrupt:
C:\Users\MrD\.PyCharm2018.2\config\scratches>c:\_\Python363-64\python.exe thread_daemon.py
0
Slept 2
1
Terminating...
Slept 2
2
Prod terminating
Uncommenting the # daemon=True line results in the prod_thread being ended immediately:
C:\Users\MrD\.PyCharm2018.2\config\scratches>c:\_\Python363-64\python.exe thread_daemon.py
0
Slept 2
1
Terminating...
My question is what is the preferred/more pythonic way to deal with thread termination - should I drop the Event machinery and just mark the thread as daemon or is there some edge case I miss?
See:
 
     
    