简体   繁体   中英

Decorator that changes certain argument of function

Working on a new version of the library I change one of the default arguments of several functions. So I'd like to add a temporary warning that occurs when user calls a function without explicitly specified parameters (so function is called with its defaults).

It could be easily done just by adding the warning function and calling it inside each of base functions:

def warning(formatting):
    if formatting is None:
        sys.stderr.write("WARNING: The default format has changed to new_format")
        return 'new_format'
    return formatting

def my_function(arg1, arg2, formatting=None):
    formatting = warning(formatting)
    ...  # the following function code

However it would be more convenient to do it using decorator (for code readability). So I've implemented something like this:

def check_default_format(fun):
    def warning(*a, **kw):
        if 'formatting' not in kw.keys() or kw['formatting'] is None:
            kw['formatting'] = 'new_format'
            sys.stderr.write("WARNING: The default format has changed to new_format")
        return fun(*a, **kw)
    return warning

@check_default_format
def my_function(arg1, arg2, formatting=None):
    ...  # the function code

That works as expected when I call my_function without formatting parameter and if formatting is specified as a keyword parameter. But how to include the possibility that my_function can be called with only positional parameters? Calling decorated my_function('arg1', 'arg2', 'some_format') will produce an TypeError due to duplication of formatting parameter.

Note: I cannot assume that the formatting is always the 3rd parameter as I need to decorate different functions. I also cannot change the parameters order to preserve backward compatibility.

In python 3, you can use the inspect module's Signature.bind_partial :

def check_default_format(fun):
    @wraps(fun)
    def wrapper(*a, **kw):
        sig= inspect.signature(fun)
        args= sig.bind_partial(*a, **kw)

        if 'formatting' not in args.arguments or args.arguments['formatting'] is None:
            kw['formatting'] = 'new_format'
            sys.stderr.write("WARNING: The default format has changed to new_format")
        return fun(*a, **kw)
    return wrapper

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