Search code examples
pythonpython-3.xtypingdelegationcallable

What is the notation for a callable instance parameter?


I am trying to find the most elegant way to help IntelliSense catch the expected set of parameters for the callables.

Consider the following piece of code:

class Box:
    def __init__(self, f: callable) -> None:
        self.f: callable = f

    def callF(self):
        self.f(self, 5, 6, 77, 65)

As one can see, the callable object f was not explicitly defined in the parameters.

I can try to fix it with the delegate:

from __future__ import annotations

class Box:

    class BoxFDelegate:
        def f(self, a:int, b:int, c:int, d:int):
            pass

    def __init__(self, f: Box.BoxFDelegate.f) -> None:
        self.f: Box.BoxFDelegate.f = f

    def callF(self):
        self.f(self, 5, 6, 77, 65)

The delegate pattern is great, but it needs to subclass the delegate elsewhere of the body of code:

class D(Box.BoxFDelegate):
    def f(self, a:int, b:int, c:int, d:int):
        ...

class Main:
    def boxing():
        boxDelegate = D()
        box = Box(boxDelegate)
        ...

As a possible variant of the delegating, is the including the delegate method into the Main class:

class Main(Box.BoxFDelegate):
    def boxing():
        box = Box(self.f)
        ...

    def f(self, a:int, b:int, c:int, d:int):
        ...

This notation is shorter, but what if I have many different class Box instances?

In the perfect world, I can accomplish such a problem with:

class Main(Box.BoxFDelegate):
    def boxing():
        boxes = [
                    Box(lambda a, b, c, d: ...),
                    Box(lambda a, b, c, d: ...),
                    Box(lambda a, b, c, d: ...),
                ]

Unfortunately, such a way is write-only.

How to be concise in types and not be brutally beaten by developers who will attempt to maintain the code later?


Solution

  • Please look at the comment from @SuperStormer. It should result in something like this:

    from __future__ import annotations
    from typing import Callable
    
    
    class Box:
        def __init__(self, f: Callable[[Box, int, int, int, int], None]) -> None:
            self.f = f
    
        def call_f(self) -> None:
            self.f(self, 5, 6, 77, 65)