Search code examples
pythondecoratorpython-decorators

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') 

Solution

  • 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.