简体   繁体   中英

Keyword arguments for function wrapped with decorator not working

All the tutorials I find on decorators suggest using *args, **kwargs in the wrapping function's signature, to handle arguments from the wrapped function. Yet kwargs are not working, while plain args are:

from functools import wraps


def wrapper(a_thing):
    @wraps(a_thing)
    def do_thing(*args, **kwargs):
        print('before')
        print(kwargs)
        value = a_thing(*args, **kwargs)
        print("after", *args, **kwargs)
        return value
    return do_thing


@wrapper
def output(*args, **kwargs):
    print('during', *args, **kwargs)

import pdb; pdb.set_trace()

Here's my interactive output:

(Pdb) output(99, 100)
before
{}
during 99 100
after 99 100
(Pdb) output(arg1=99, arg2=100)
before
{'arg1': 99, 'arg2': 100}
*** TypeError: 'arg1' is an invalid keyword argument for this function
(Pdb)

Here's an example of one of many such tutorials:

What's the point of using **kwargs if it doesn't work? I feel like I'm missing something.

You don't want to unpack in the calls to print ; print only accepts a limited number of keyword arguments, and will reject all others. Presumably you just want to see what was passed, so print the raw tuple and dict without unpacking:

def wrapper(a_thing):
    @wraps(a_thing)
    def do_thing(*args, **kwargs):
        print('before')
        print(kwargs)
        value = a_thing(*args, **kwargs)
        print("after", args, kwargs)  # Removed unpacking
        return value
    return do_thing


@wrapper
def output(*args, **kwargs):
    print('during', args, kwargs)  # Removed unpacking

The point of unpacking is that it passes the elements of a * unpacked iterable as sequential positional arguments, and the key value pairs from a ** unpacked mapping using the keys as keyword arguments, and the values as the associated value. So when you did:

    print('during', *args, **kwargs)

having called into the function with output(arg1=99, arg2=100) , it was as if you ran:

    print('during', arg1=99, arg2=100)

Neither arg1 nor arg2 are keywords accepted by print , so it screamed at you. By removing the unpacking, the print becomes equivalent to:

    print('during', (), {'arg1': 99, 'arg2': 100})

which is perfectly valid (it's printing the tuple and dict directly, not trying to unpack).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM