2

I have a function, say:

def func(arg1, arg2=5):
    blah blah

Unfortunately, a library that I'm using asks for an input to be instance of a class, so I cannot just pass my custom made function above.

I need a class wrapper around it, so that I pass: MyClass(arg2=4) and the result is the function shown above, ready to be executed with its second argument set to 4.

How can I do that?

My attempt: lambda x: func(x, arg2=4)

However, this is not an instance of a class. I want to mimic that library where their functions are instances of classes.

DennisLi
  • 3,915
  • 6
  • 30
  • 66
Alex Deft
  • 2,531
  • 1
  • 19
  • 34
  • 1
    Please check the following link: https://stackoverflow.com/questions/1466676/create-a-wrapper-class-to-call-a-pre-and-post-function-around-existing-functions/1467296 – b107 Aug 07 '19 at 06:14

2 Answers2

5

you can use the __call__ function of a class.

class CallableObject(object):
    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kwargs):
        return self.f(*args, **kwargs)

then you can "call" the class like this:

def func(arg1, arg2=5):
    return arg1 + arg2

callable_object = CallableObject(func)
callable_object(1, 3)

returns 4

args in __init__

To give arguments when instantiating the class you can add them to init.

class CallableObject(object):
    def __init__(self, f, *args, **kwargs):
        self.f = f
        self.args = args
        self.kwargs = kwargs

    def __call__(self):
        return self.f(*self.args, **self.kwargs)

Usage then becomes:

def func(arg1, arg2=5):
    return arg1 + arg2

callable_object = CallableObject(func, 1, arg2=3)
callable_object()

returning 4

and you can still call

def func(arg1, arg2=5):
    return arg1 + arg2

callable_object = CallableObject(func, 1)
callable_object()

returning 6 (arg2 = 5)

Laurens Koppenol
  • 2,946
  • 2
  • 20
  • 33
2

Using metaclass, you can solve this

class MetaClass(type):
    @staticmethod
    def wrap(run):
        """Return a wrapped instance method"""
        def outer(self):
            print "PRE",
            return_value = run(self)
            print "POST"
            return return_value
        return outer
    def __new__(cls, name, bases, attrs):
        """If the class has a 'run' method, wrap it"""
        if 'run' in attrs:
            attrs['run'] = cls.wrap(attrs['run'])
        return super(MetaClass, cls).__new__(cls, name, bases, attrs)

    class MyClass(object):
        """Use MetaClass to make this class"""
        __metaclass__ = MetaClass
        def run(self): print 'RUN',

    myinstance = MyClass()


    myinstance.run()
Laurens Koppenol
  • 2,946
  • 2
  • 20
  • 33
Abin Abraham
  • 497
  • 2
  • 11
  • 26