React Context API in Python

When you are deep down in a function inside a function inside another function and you need something from the first function, you need to pass it all the way down to the last function. But with the concept of React Context, you create a variable that you can retrieve at any level without the need to pass it down. Better than a global variable, more flexible than a class or using nonlocal.

Here’s a demo of what it looks like in Python. I think the idea is so good it should be built-in in a next version of Python and I will try to propose a PEP if people like this.

### LIBRARY ###

from contextlib import contextmanager

CURRENT_CONTEXT = {}
@contextmanager
def use_context(**kwargs):
    global CURRENT_CONTEXT
    try:
        for key, value in kwargs.items():
            CURRENT_CONTEXT[key] = value
        yield
    finally:
        for key, value in kwargs.items():
            del CURRENT_CONTEXT[key]


def get_context(key):
    global CURRENT_CONTEXT
    return CURRENT_CONTEXT[key]

####################################

### USAGE ###

def do_something_with_current_user(user):
    print(user)


def another_function():
    user = get_context('user')
    do_something_with_current_user(user)


def function_between():
    another_function()


def first_function():
    user = "vicky"
    with use_context(user=user):
        function_between()

EDIT: Of course this version doesn’t work with multiple threads

As it happens, Yuri already wrote a PEP for something very similar: contextvars.

Thanks, it doesn’t look as clean, maybe I don’t know how to use it well, here’s my example transformed to look use contextvars:

import contextvars

user_var = contextvars.ContextVar('user')

def do_something_with_current_user(user):
    print(user)


def another_function():
    user = user_var.get()
    do_something_with_current_user(user)


def function_between():
    another_function()


def first_function():
    user = "vicky"
    token = user_var.set(user)
    function_between()
    user_var.reset(token)

When you are deep down in a function inside a function inside another function and you need something from the first function, you need to pass it all the way down to the last function. But with the concept of React Context, you create a variable that you can retrieve at any level without the need to pass it down. Better than a global variable, more flexible than a class or using nonlocal.

Here’s a demo of what it looks like in Python. I think the idea is so good it should be built-in in a next version of Python and I will try to propose a PEP if people like this.

### LIBRARY ###

from contextlib import contextmanager

CURRENT_CONTEXT = {}
@contextmanager
def use_context(**kwargs):
    global CURRENT_CONTEXT

You say that this is “better than a global variable” but in the demonstration it is just a function wrapping a global variable. The example as shown would suffer all the same problems as a global variable such as non-reentrancy.

If the context manager is used over the top of itself then it clobbers everything e.g.:

def func1():
    with use_context(user='foo'):
        func2()
        # func2 has wiped the user key so this will raise:
        func3()

def func2():
    with use_context(user='bar'):
        func4()

def func4():
    return

def func3():
    user = get_context('user')

Here it’s a toy implementation, it’s easy to fix the double calling of use_context in the implementation.

I agree, it’s not yet ready for a PEP :slight_smile:, just throwing the idea around to see if other people like it.

1 Like

It certainly looks convenient, but newcomers to code which would use this feature would have a hard time find where the context values are set.

1 Like