0

I'm looking for a way to decorate an arbitrary python function, so that an alternate function is called instead of the original, with all parameters passed as a list or dict.

More precisely, something like this (where f is any function, and replacement_f takes a list and a dict):

def replace_func(f, replacement_f):
    def new_f(*args, **kwargs):
        replacement_f(args, kwargs)
    return new_f

However, I cannot reference replacement_f inside new_f. And I can't use the standard trick of passing replacement_f to new_f as the default for a different parameter, because I'm using the *args and **kwargs variable argument lists.

The location where the original function is called cannot change, and will accept both positional and named parameters.

I fear that isn't very clear, but I'm happy to clarify if needed.

Thanks

Mzzzzzz
  • 4,770
  • 7
  • 30
  • 47
  • you are right: this is not clear. i think you don't need to change the call of the original function, but rather its definition. if you can't change that, you probably can't decorate it either. –  Aug 18 '09 at 17:58
  • thanks all. I was making this far too difficult, I can just replace the function without all the *args, **kwargs hassle. Also, I think the scope rules have changed since Python 1.x, now I can reference a variable from the outer function inside the inner function definition. – Mzzzzzz Aug 18 '09 at 18:08

4 Answers4

4

why don't you just try:

f = replacement_f

example:

>>> def rep(*args):
    print(*args, sep=' -- ')

>>> def ori(*args):
    print(args)

>>> ori('dfef', 32)
('dfef', 32)
>>> ori = rep
>>> ori('dfef', 32)
dfef -- 32
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
1

Although I think SilentGhost's answer is the best solution if it works for you, for the sake of completeness, here is the correct version of what you where trying to do:

To define a decorator that takes an argument, you have to introduce an additional level:

def replace_function(repl):
    def deco(f):
        def inner_f(*args, **kwargs):
            repl(*args, **kwargs)

        return inner_f
    return deco

Now you can use the decorator with an argument:

@replace_function(replacement_f)
def original_function(*args, **kwargs):
    ....
0

If I understand this correctly, you want to pass all arguments from one function to another.

Simply do:

def replace_func(f, replacement_f):
    def new_f(*args, **kwargs):
        replacement_f(*args, **kwargs) # args & kwargs will be expanded
    return new_f
Jeff
  • 5,013
  • 1
  • 33
  • 30
0

does this do what you mean? Untested

def replace_func(f, replacement_f):
    nonlocal replacement_f  #<<<<<<<<<<<<<<<py3k magic
    def new_f(*args, **kwargs):
        replacement_f(*args, **kwargs) # args & kwargs will be expanded
    replacement_f = new_f

Python nonlocal statement

edit: its a start, im confused exactly what you want, but i think nonlocal will help

Community
  • 1
  • 1
Dustin Getz
  • 21,282
  • 15
  • 82
  • 131