I want to put single-dispatch method in functools module with abstract method in abc module in one method in my abstract class and then using the method in my subclasses based on first argument type. but the problem is the dispatch method doesn't works.
class Abstract(metaclass=ABCMeta):
...
...
...
@singledispatchmethod
@abstractmethod
def apply(self, element:str):
raise NotImplementedError
@apply.register
@abstractmethod
def _(self, element: int):
raise NotImplementedError
class A(Abstract):
def apply(self, element: str):
print(f'this is string -> {element}')
def _(self, element: int):
print(f'this is intiger -> {element}')
>>>instance = A()
>>>instance.apply(2)
#will return (this is string -> 2)
i have solved this problem in other way but i'm curious about this problem if it has an answer
I was curious to find this out, because I just worked on a project where I wanted to have this feature, because I was porting an app from C# where I could simply use overloads. I got this behaviour to work with two different approaches:
This is the version that I needed, which makes the dispatchmethod abstract and every derived class thus also has to define a concrete dispatchmethod with the same signature (important: these are now separate dispatch methods and can provide different registrations). Also note that, because these are concrete, every derived class has their own dispatch and the function in the DoerBase
is never called (as it is only abstract).
from abc import ABC, abstractmethod
from functools import singledispatchmethod
from typing import Any
from typing_extensions import override
class DoerBase(ABC):
@singledispatchmethod
@abstractmethod
def do_something(self, arg: Any) -> None: ...
class IntDoer(DoerBase):
@singledispatchmethod
@override
def do_something(self, arg: Any) -> None:
raise NotImplementedError(f"This {type(self).__name__} cannot do anything with a {type(arg).__name__}!")
@do_something.register
def _(self, arg: int):
print("The number", arg, "is half of", 2 * arg)
class StringDoer(DoerBase):
@singledispatchmethod
@override
def do_something(self, arg: Any) -> None:
raise NotImplementedError(f"This {type(self).__name__} cannot do anything with a {type(arg).__name__}!")
@do_something.register
def _(self, arg: str):
print("I can print this string for you:", arg)
def main():
int_doer = IntDoer()
string_doer = StringDoer()
int_doer.do_something(321)
string_doer.do_something("Hello")
# This IntDoer cannot do anything with a str!
# int_doer.do_something("Hello")
# This StringDoer cannot do anything with a int!
# string_doer.do_something(321)
if __name__ == "__main__":
main()
The version which is more similar to the one in your example declares the registered dispatch types in the base class (the above method declares registrations per derived class). Now every base class must override the abstract dispatch registrations. I was able to recreate this behaviour by calling an abstract method from the registered dispatch handler instead of trying to make the dispatch handler itself abstract.
from abc import ABCMeta, abstractmethod
from functools import singledispatchmethod
from typing import Any
class ABase(metaclass=ABCMeta):
@singledispatchmethod
def apply(self, element: Any) -> None: ...
@apply.register
def _(self, element: int): return self.apply_int(element)
@abstractmethod
def apply_int(self, element: int) -> None: ...
class A(ABase):
def apply_int(self, element: int):
print("I applied the number", element)
class B(ABase): pass
instance = A()
instance.apply(2)
#will print "I applied the number 2"
# b_instance = B()
# TypeError: Can't instantiate abstract class B with abstract method apply_int
@singledispatchmethod
decorator@method.register
decorator with the @abstractmethod
decorator@abstractmethod
decorator