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
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')
I coded a library inspired by this post that works in several scenarios.
It also exposes a debug mode to understand where the context has been defined in the upper functions.