How to use `self` as a function, like `self(**data)` in the example code

Question:

Here is part of code from mmcv (mmcv/runner/base_module.py).

I don’t understand how does self(**data) works.


class BaseDetector(BaseModule, metaclass=ABCMeta):
    """Base class for detectors."""

    # ...

    def train_step(self, data, optimizer):
     
        losses = self(**data)
        loss, log_vars = self._parse_losses(losses)

        outputs = dict(
            loss=loss, log_vars=log_vars, num_samples=len(data['img_metas']))

        return outputs
class BaseModule(nn.Module, metaclass=ABCMeta):
    def __init__(self, init_cfg: Optional[dict] = None):
    # ...

Tried to find some function like __call__ in the parent class, but it seems not the right direction to go.

Could any one explain why self could be used as a function?

Asked By: zheyuanWang

||

Answers:

This is nothing specific to PyTorch but rather to how Python works.

"Calling" an object is equivalent to calling a special Python function named __call__. Essentially, this is the function which implements the call behaviour. In your case self(**data) will call BaseDetector‘s __call__ function which has most probably been implemented by one of the parent classes.

Here is a minimal example to understand this behaviour:

class A():
    def __call__(self):
        return 'hello'

class B(A):
    def foo(self):
        return self() + ' world'

Initialize a new object from B:

b = B()

Then let us call the foo method on b:

>>> b.foo()
'hello world'

This function has been calling b() i.e. b.__call__():

>>> b() # same as b.__call__()
'hello'

As an additional note, you can explicitly call the implementation of the parent class. This is useful when you need to overload the original implementation in your child’s class.

It is done by calling super:

class A():
    def __call__(self):
        return 'hello'

class B(A):
    def __call__(self):
        # calling self() here would create an infinite recursion loop
        return super().__call__() + ' world' 

Then you can call an instance of B the same way:

>>> b = B()
>>> b()
'hello world'
Answered By: Ivan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.