Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use singledispatchmethod with inheritance class

In my code, I have the following class:

class A:
  @functools.singledispatchmethod
  def handle(arg):
     pass

I want other class to inherit from A and overload the generic method handle like so:

class B(A):
   @handle.register
   def handle_int(arg: int):
       return arg + 2

However, I get an error:

unresolved reference 'handle'

How can I create this generic method in the base class? (I don't want to create this function in every subclass to use the singledispatchmethod.)

like image 356
Yedidya kfir Avatar asked Apr 30 '26 10:04

Yedidya kfir


1 Answers

Not ideal approach

Since you are referring to the method defined in class A you have to indicate it using @A.handle.register:

class B(A):
   @A.handle.register
   def handle_int(arg: int):
       return arg + 2
Issue

But this approach causes issues when there is another class C, also inheriting from A but supporting handle(arg: str). Then C().handle(2) will call method from class B since it was registered to A method (even though it should end up in class A base handle method).

Much better approach

The apparent issue with the solution above is one registering class (A), so I am adding registering in all derivative classes but leave the processing to the base class in case there are no proper type-specialized class methods in the derivative classes.

import functools

class A:
  @functools.singledispatchmethod
  def handle(arg):
     print(f'\tA handle (arg: {arg})')

class B(A):
    @functools.singledispatchmethod
    @classmethod
    def handle(cls, arg):
        print(f'\tB handle (arg: {arg})')
        return super(B, cls).handle(arg)


@B.handle.register
def handle_int(arg: int):
    print(f'\tB int (arg: {arg})')
    return arg + 2


class C(A):
    @functools.singledispatchmethod
    @classmethod
    def handle(cls, arg):
        print(f'\tC handle (arg: {arg})')
        return super(C, cls).handle(arg)

@C.handle.register
def handle_str(arg: str):
    print(f'\tC str (arg: {arg})')
    return arg + ' 2'

print('\nA')
A.handle(2)
A.handle('2+')

print('\nB')
B.handle(2)
B.handle('2+')

print('\nC')
C.handle(2)
C.handle('2+')

Result:

A
    A handle (arg: 2)
    A handle (arg: 2+)

B
    B int (arg: 2)
    B handle (arg: 2+)
    A handle (arg: 2+)

C
    C handle (arg: 2)
    A handle (arg: 2)
    C str (arg: 2+)
like image 117
sophros Avatar answered May 03 '26 00:05

sophros



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!