Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Decorator override function argument

I'm am trying to write a python decorator to override a function argument, but I'm really lost to what to be put inside the inner() function. What's the proper way to modify args here?

  def override(*override_args, **override_kwargs): 
        def outer(f): 
            def inner(*args, **kwargs): 
                ...
                ...
            return inner
        return outer

    @override('Cat')
    def my_function(animal, **kwargs): 
        print animal
        print kwargs

    my_function('Mouse', k1='1', k2='10') 
like image 940
user1187968 Avatar asked Mar 09 '23 19:03

user1187968


2 Answers

def override(*override_args, **override_kwargs):
    def outer(f):
        def inner(*args, **kwargs):
            min_args_length = min(len(args), len(override_args))
            args = list(args)
            for i in xrange(min_args_length):
                args[i] = override_args[i]
            kwargs.update(override_kwargs)
            return f(*args, **kwargs)
        return inner
    return outer

@override('Cat', 'male', k1='0')
def my_function(animal, **kwargs):
    print animal
    print kwargs

my_function('Mouse', k1='1', k2='10')

output:

Cat
{'k2': '10', 'k1': '0'}

explain:

args is a tuple contains args without name, we can override at most min(len(args), len(override_args)) of them.

kwargs is a dict contains named args as key : value pairs. Just update override_kwargs to kwargs

And I strongly suggest you only override named args "kwargs" to prevent mismatch args' order.

like image 156
Valens Avatar answered Mar 12 '23 07:03

Valens


class override_func_params(object):
    def __init__(self, *args, **kwargs):
        self.override_args = args
        self.override_kwargs = kwargs

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            if kwargs:
                kwargs.update(self.override_kwargs)
            if args:
                args = list(args)
                for index, value in enumerate(self.override_args):
                    try:
                        args[index] = value
                    except IndexError:
                        break
                args = tuple(args)
            return func(*args, **kwargs)
        return wrapper


@override_func_params('a', k=1)
def foo(*args, **kwargs):
    print args, kwargs

Call without arguments.

>>> foo()
>>> (), {}

Call with arguments, the arguments are overrided.

>>> foo('b', k=2)
>>> ('a',), {'k': 1}
like image 39
fatelei Avatar answered Mar 12 '23 08:03

fatelei