1

Here is the code:

# Decorators
def on_or_off(func):
    def wrapper(*args, on_switch, **kwargs):
        if on_switch:
            func(*args, on_switch=on_switch, **kwargs)
    return wrapper

@on_or_off
def print_101(on_switch=False):
    print ('101')

print_101()

# TypeError: wrapper() missing 1 required keyword-only argument: 'on_switch'

I thought the default on_switch value will pass to the wrapper function, but it doesn't. How can the line print_101() remains the same and allows for passing the default on_switch value to the wrapper decorator function?

KubiK888
  • 4,377
  • 14
  • 61
  • 115

1 Answers1

1

on_switch is keyword-only, you declared it as such by using *args before it.

print_101 now refers to the wrapper function, which is missing the on_switch argument, because it's required.

You can solve this by declaring its default value inside the wrapper:

# Decorators
def on_or_off(func):
    def wrapper(*args, on_switch=False, **kwargs):
        if on_switch:
            func(*args, on_switch=on_switch, **kwargs)
    return wrapper

Theoretically, you could look into func.__defaults__ or use the inspect module to automatically figure out the default value, but that's probably overkill:

# Decorators
def on_or_off(func):
    bindings = dict(zip(func.__code__.co_varnames, func.__defaults__))
    bindings.update(func.__kwdefaults__)
    def wrapper(*args, on_switch=bindings["on_switch"], **kwargs):
        if on_switch:
            func(*args, on_switch=on_switch, **kwargs)
    return wrapper
L3viathan
  • 26,748
  • 2
  • 58
  • 81