How can I make a class object callable in Python?

Question:

How can you define in Python3 a class MyClass such that you instantiate it like
obj = MyClass(param1, param2) and then use it to compute an operation like res = obj(in1, in2, in3) ?

For instance, with PyTorch you can declare a model as mod = MyResNet50() and then compute its prediction as pred = mod(input).

Below is the code I tried. I declare a method and call it as obj.method().

import numpy as np


class MLP:

    def __init__(self, hidden_units: int, input_size: int):
        self.hidden_units = hidden_units
        self.input_size = input_size
        self.layer1 = np.random.normal(0, 0.01, size=(hidden_units, input_size))
        self.layer2 = np.random.normal(0, 0.01, size=(1, hidden_units))

    def sigmoid(self, z):
        return 1/(1 + np.exp(-z))

    def predict(self, input):
        pred = self.layer1.dot(input)
        pred = self.layer2.dot(pred)
        return self.sigmoid(pred)

my_MLP = MLP(5, 10)
pred = my_MLP.predict(np.random.normal(0, 0.01, 10))
Asked By: Álvaro F. b.f.

||

Answers:

Implement __call__ to react to the class instance being called with ():

class MyClass:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def __call__(self, in1, in2, in3):
        return f'Hello, this is {self.p1} {self.p2}. You rang? {in1} {in2} {in3}'

Example:

>>> obj = MyClass('Foo', 'Bar')
>>> res = obj(1, 2, 3)
>>> res
'Hello, this is Foo Bar. You rang? 1 2 3'

If your class instance does not have __call__ defined (either itself or what it descends from) it will let you know:

class MyClass:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    # no other methods and only descendant of `object`...
>>> MyClass('Foo', 'Bar')()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'MyClass' object is not callable
Answered By: dawg

for call back use the __call__ and for the mod use __mod__ function.

class MyClass:
    def __init__(self, param1, param2):
        self.param1, self.param2 = param1, param2
        print(self.param1, self.param2)

    def __call__(self, in1, in2, in3):
        self.result = '%s, %s, %s' % (in1, in2, in3)
        print(in1, in2, in3)
        return self

    def __mod__(self, other):
        return other


obj = MyClass('param1', 'param2')  # -> param1 param2
res = obj('in1', 'in2', 'in3')  # -> in1 in2 in3
print(res % 5)  # -> 5
Answered By: arasemco