January 5, 2015

Understanding the frame parameter in python signal handlers

According to the documentation of python’s signal module, signal handlers accept two parameters. One is the obvious signum. Another is the frame. What does it do? Is it some unnecessary implementation details that you should ignore? The documentation is not very clear about it’s use cases.

frame is the way to know about the state of execution before the signal handler was triggered. Since a signal is usually an asynchronous, external event, you can not make any assumptions about the state of execution while handling a signal. Actually, you don’t need to; as the information about the state of the execution is sent to the signal handler through the frame parameter. Using the frame, a signal handler can read states inside the scope that was being executed before the signal handler was triggered. An example will clarify the process -

#!python
# file: signal_frame_demo.py
import signal
from time import sleep

def signal_handler(signum, frame):
    print(
        "Execution inside '{0}', "
        "with local namespace: {1}"
        .format(frame.f_code.co_name, frame.f_locals.keys()))

# Set a repeatitive alarm signal with 1 second interval.
signal.signal(signal.SIGALRM, signal_handler)
signal.setitimer(signal.ITIMER_REAL, 1.0, 1.0)

while True:
    def my_first_sleepy_function():
        # Some useless local variables to polute the namespace.
        a, b, c = (1, 2, 3)
        sleep(2.0)


    def my_second_sleepy_function():
        # Some useless local variables to polute the namespace.
        x, y, z = (101, 102, 103)
        sleep(2.0)

    my_first_sleepy_function()
    my_second_sleepy_function()

    # sleep in the global namespace.
    sleep(2.0)

Executing the above script prints something like this -

Execution inside 'my_first_sleepy_function', with local namespace: dict_keys(['b', 'c', 'a'])
Execution inside 'my_second_sleepy_function', with local namespace: dict_keys(['y', 'x', 'z'])
Execution inside '<module>', with local namespace: dict_keys(['__builtins__', 'my_first_sleepy_function', '__file__', '__package__', 'signal', '__spec__', 'signal_handler', '__name__', '__cached__', 'my_second_sleepy_function', '__doc__', 'sleep', '__loader__'])
...
...

Caution

frame and most of it’s items are read only. For example, you can not add a new variable to the execution environment by modifying frame.f_locals.

Tags: Python , Programming