WhileTrueDoEnd
WhileTrueDoEnd

Reputation: 3

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

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'}

Upvotes: 0

Views: 164

Answers (1)

anthony sottile
anthony sottile

Reputation: 70107

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}

Upvotes: 2

Related Questions