Using Threading.Event to signal main thread
Yes and no. Your approach works, and it is easy to understand. If, however, you want to keep track of what type of exception was raised, it could be improved. What if you have some super complex function that can raise 10 different exceptions, and you need access to the exception traceback if something goes wrong? You'd need 10 threading.Event instances. In that case, you should use a queue.Queue instead, which is thread-safe (untested snippet):

import queue
import threading

def dividebyzero(first, second, exc_queue):
    try:
        result = first / second
    except ZeroDivisionError as exc:
        exc_queue.put(exc)
    else:
        print(result)

excq = queue.Queue()
t = threading.Thread(target=dividebyzero, args=(10, 0, excq))
t.start()
t.join()
if excq.qsize() != 0:
    print(excq.get())

No, it is not mandatory to use threading.Event.wait(). Your observation is right: calling event.wait() might make the thread hang indefinitely.
goto 1;