human
Write me a the Python code you requested given the following:
I am working on the file "Extending_lolviz_with_a_unified_display_function_that_chooses_the_best_one_based_on_the_datatype.ipynb".
The first task is:
Okay, by using the optional frame= argument of lolviz.callviz, and some sys._getframe black magic, we can do this!

See https://code.activestate.com/recipes/579105-how-a-python-function-can-find-the-name-of-its-cal/

Can we write a @show_recursion function decorator, to automatically do this visualization of recursive calls for us?
Can you write Python code for it?
assistant
#Here is the Python code you requested.

def show_recursion(varnames=None):
    def showing_recursion_with_varnames(function):
        nonlocal varnames
        # https://stackoverflow.com/questions/582056/getting-list-of-parameter-names-inside-python-function#4051447
        if varnames is None:
            varnames = function.__code__.co_varnames
        import lolviz
        from IPython.display import display
        from functools import wraps
        @wraps(function)
        def wrapped_function(*args, **kwargs):
            nonlocal display, wraps, varnames, lolviz
            ##print(f"args = {args}, of type = {type(args)}")
            ##print(f"kwargs = {kwargs}, of type = {type(kwargs)}")
            #print(f"varnames = {varnames}")
            display(lolviz.callsviz(varnames=varnames))
            return function(*args, **kwargs)
        return wrapped_function
    return showing_recursion_with_varnames

@show_recursion()
def factorial4(n, f0=0, f1=1):
    # this is automatically done: display(viz(varnames=["n"], mode="call"))
    if n < 0: return f0
    elif n == 0: return f1
    else: return n * factorial4(n - 1, f0=f0, f1=f1)
    
n = 4
print(f"{n}! = {factorial4(n)}")