Home > Net >  Instance is not passed to the `__call__` function of a callable class
Instance is not passed to the `__call__` function of a callable class

Time:04-28

Why ClassWithCallable instance isn't passed to the __call__ function? How can I make that happen?

class Callable:
    def __call__(self, *args, **kwargs):
        print(self, args, kwargs)
        print('Where is `ClassWithCallable` instance?')


class ClassWithCallable:
    method = Callable()


instance = ClassWithCallable()
instance.method('some', data='data')
instance.method(instance, 'some', data='data') #  ugly :(

Output:

<__main__.Callable object at 0x7f2b4e5ecfd0> ('some',) {'data': 'data'}
Where is `ClassWithCallable` instance?
<__main__.Callable object at 0x7fef7fa49fd0> (<__main__.ClassWithCallable object at 0x7fef7fa49fa0>, 'some') {'data': 'data'}

CodePudding user response:

in order to "bind" self, you need to implement the descriptor protocol (similar to how an actual method works!)

class Callable:
    def __init__(self, inst=None):
        self.inst = inst

    def __get__(self, instance, owner):
        return type(self)(instance)

    def __call__(self, *args, **kwargs):
        print(self.inst, args, kwargs)


class C:
    callable = Callable()


C().callable(1, a=2)

when the attribute is retrieved, it calls the __get__ of your descriptor -- my implementation returns a "bound" version of Callable where self.inst is the self you seek

example output:

$ python3 t.py
<__main__.C object at 0x7f3051529dc0> (1,) {'a': 2}

CodePudding user response:

I am unsure of your actual requirement. But a simple way would be to let method be a mere reference to a true method:

class ClassWithCallable:
    method = Callable.__call__

From that point,

instance = ClassWithCallable()
instance.method('some', data='data')

gives as expected:

<__main__.ClassWithCallable object at 0x0000023542A76548> ('some',) {'data': 'data'}
Where is `ClassWithCallable` instance?
  • Related