5

There are some interesting ways to run a method before every method in a class in questions such as Python: Do something for any method of a class?

However that solution doesn't let us pass arguments.

There's a decorator solution on Catch "before/after function call" events for all functions in class but I don't want to have to go back and decorate all my classes.

Is there a way to run a pre/post operation that's dependent on the arguments passed for every invocation of an object's method?

Example:

class Stuff(object):
    def do_stuff(self, stuff):
        print(stuff)

a = Stuff()
a.do_stuff('foobar')
"Pre operation for foobar"
"foobar"
"Post operation for foobar"
Community
  • 1
  • 1
wonton
  • 7,568
  • 9
  • 56
  • 93

1 Answers1

3

So I figured it out after a lot of experimentation.

Basically in the metaclass' __new__ you can iterate through every method in the class' namespace and swap out every method in the class being created with a new version that runs the before logic, the function itself, and the after logic. Here's a sample:

class TestMeta(type):
    def __new__(mcl, name, bases, nmspc):
        def replaced_fnc(fn):
            def new_test(*args, **kwargs):
                # do whatever for before function run
                result = fn(*args, **kwargs)
                # do whatever for after function run
                return result
            return new_test
        for i in nmspc:
            if callable(nmspc[i]):
                nmspc[i] = replaced_fnc(nmspc[i])
        return (super(TestMeta, mcl).__new__(mcl, name, bases, nmspc))

Note that if you use this code as is it will run the pre/post operation for init and other builtin functions as well.

wonton
  • 7,568
  • 9
  • 56
  • 93