如何在继承类中使用 singledispatchmethod

问题描述

在我的代码中,我有以下类

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

我希望其他类继承自类 A 并像这样重载泛型方法 handle

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

但是我得到一个错误

未解析的引用“句柄”

如何在基类中创建这个泛型方法(我不想在每个子类中都创建这个函数来使用singledispatchmethod) 谢谢

解决方法

不理想的方法

由于您指的是在类 A 中定义的方法,因此您必须使用 @A.handle.register 来指示它:

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

但是当存在另一个类 C 时,这种方法会导致问题,该类也继承自 A 但支持 handle(arg: str)。然后 C().handle(2) 将调用类 B 中的方法,因为它已注册到 A 方法(即使它最终应该在类 A 基句柄方法中)。

更好的方法

上述解决方案的明显问题是一个注册类 (A),因此我在所有派生类中添加注册,但将处理留给基类,以防没有适当的类型专用类方法在派生类中。

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+')

结果:

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+)
,

在 Python 中实现您想要做的事情有点困难。 singledispatchsingledispatchmethod 本身都是该语言中相对的新功能。更复杂的重载(例如您正在尝试的操作)目前还没有特别得到很好的支持(据我所知)。

话虽如此,您可以使用第三方 multipledispatch module 尝试以下操作。不过,这感觉有点像 hack,而且我不确定如何使其适用于类方法——以下解决方案仅适用于实例方法。

from multipledispatch import dispatch

@dispatch(object,object)
def handle(instance,arg):
    return 'Base implementation'
        
class A:
    def handle(self,arg):
        return handle(self,arg)

class B(A):
    pass

class C(A):
    pass

@dispatch(B,int)
def handle(instance,arg):
    return 'Specialised implementation for class B and ints'

@dispatch(C,str)
def handle(instance,arg):
    return 'Specialised implementation for class C and strs'

a,b,c = A(),B(),C()

print(a.handle('hi')) # prints "Base implementation"
print(b.handle('hi')) # prints "Base implementation"
print(b.handle(3)) # prints "Specialised implementation for class B and ints"
print(c.handle(3)) # prints "Base implementation"
print(c.handle('hi')) # prints "Specialised implementation for class C and strs"

使用 pip 上的另一个第三方模块 plum-dispatch module,您或许能够更接近您想要的结果。我对它了解不多,但我认为它有一些 multipledispatch 没有的额外功能。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...