Nick Chapman
Nick Chapman

Reputation: 4634

Python: How do you intercept a method call to change function parameters?

What I am trying to do is write a wrapper around another module so that I can transform the parameters that are being passed to the methods of the other module. That was fairly confusing, so here is an example:

import somemodule

class Wrapper:
    def __init__(self):
        self.transforms = {}
        self.transforms["t"] = "test"

    # This next function is the one I want to exist
    # Please understand the lines below will not compile and are not real code
    def __intercept__(self, item, *args, **kwargs):
        if "t" in args:
            args[args.index("t")] = self.transforms["t"]
        return somemodule.item(*args, **kwargs)

The goal is to allow users of the wrapper class to make simplified calls to the underlying module without having to rewrite all of the functions in the module. So in this case if somemodule had a function called print_uppercase then the user could do

w = Wrapper()
w.print_uppercase("t")

and get the output

TEST

I believe the answer lies in __getattr__ but I'm not totally sure how to use it for this application.

Upvotes: 4

Views: 3448

Answers (3)

Mike Müller
Mike Müller

Reputation: 85492

__getattr__ combined with defining a function on the fly should work:

# somemodule

def print_uppercase(x):
    print(x.upper())

Now:

from functools import wraps

import somemodule

class Wrapper:
    def __init__(self):
        self.transforms = {}
        self.transforms["t"] = "test"

    def __getattr__(self, attr):
        func = getattr(somemodule, attr)
        @wraps(func)
        def _wrapped(*args, **kwargs):
            if "t" in args:
                args = list(args)
                args[args.index("t")] = self.transforms["t"]
            return func(*args, **kwargs)
        return _wrapped


w = Wrapper()
w.print_uppercase('Hello')
w.print_uppercase('t')

Output:

HELLO
TEST

Upvotes: 3

keredson
keredson

Reputation: 3088

Since your Wrapper object doesn't have any mutable state, it'd be easier to implement without a class. Example wrapper.py:

def func1(*args, **kwargs):
  # do your transformations
  return somemodule.func1(*args, **kwargs)

Then call it like:

import wrapper as w
print w.func1('somearg')

Upvotes: 0

Cary Shindell
Cary Shindell

Reputation: 1386

I would approach this by calling the intercept method, and entering the desired method to execute, as a parameter for intercept. Then, in the intercept method, you can search for a method with that name and execute it.

Upvotes: 0

Related Questions