python 3.8中的singledispatchmethod和类方法修饰符

2024-09-28 22:28:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用python 3.8的一个新功能(目前使用的是3.8.3)。在the documentation之后,我尝试了文档中提供的示例:

from functools import singledispatchmethod
class Negator:
    @singledispatchmethod
    @classmethod
    def neg(cls, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    @classmethod
    def _(cls, arg: int):
        return -arg

    @neg.register
    @classmethod
    def _(cls, arg: bool):
        return not arg

Negator.neg(1)

但是,这会产生以下错误:

...
TypeError: Invalid first argument to `register()`: <classmethod object at 0x7fb9d31b2460>. Use either `@register(some_class)` or plain `@register` on an annotated function.

如何创建泛型类方法?我的例子中有没有遗漏什么

更新:

我读过Aashish A的回答,这似乎是一个持续的问题。我已经设法用下面的方法解决了我的问题

from functools import singledispatchmethod
class Negator:
    @singledispatchmethod
    @staticmethod
    def neg(arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(arg: int):
        return -arg

    @neg.register
    def _(arg: bool):
        return not arg

print(Negator.neg(False))
print(Negator.neg(-1))

这在版本3.8.1和3.8.3中似乎有效,但似乎不应该,因为我在两个undescore函数上都没有使用staticmethod decorator。这确实适用于类方法,即使问题似乎表明了相反的情况

请记住,如果您使用的是IDE,linter不会对这种方法感到满意,会抛出很多错误


Tags: 方法fromimportregisterreturndefargclass
3条回答

在未合并错误修复程序的情况下,一种解决方法是修补^{}.register()

from functools import singledispatchmethod

def _register(self, cls, method=None):
    if hasattr(cls, '__func__'):
        setattr(cls, '__annotations__', cls.__func__.__annotations__)
    return self.dispatcher.register(cls, func=method)

singledispatchmethod.register = _register

这似乎是this issue中记录的functools库中的一个bug

Python中不再存在此错误>;=3.10. 通过改变classmethod相对于所包装函数的__annotations__属性的行为方式,该错误似乎已经得到了解决

在Python 3.9中:

>>> x = lambda y: y
>>> x.__annotations__ = {'y': int}
>>> c = classmethod(x)
>>> c.__annotations__
Traceback (most recent call last):
  File "<pyshell#37>", line 1, in <module>
    c.__annotations__
AttributeError: 'classmethod' object has no attribute '__annotations__'

在Python 3.10中:

x = lambda y: y
x.__annotations__ = {'y': int}
c = classmethod(x)
c.__annotations__
{'y': <class 'int'>}

这一变化似乎解决了singledispatchmethod的问题。在Python中>;=3.10,以下代码现在可以正常工作:

from functools import singledispatchmethod

class Negator:
    @singledispatchmethod
    @classmethod
    def neg(cls, arg):
        raise NotImplementedError(f"Cannot negate object of type '{type(arg).__name__}'")

    @neg.register
    @classmethod
    def _(cls, arg: int) -> int:
        return -arg

    @neg.register
    @classmethod
    def _(cls, arg: bool) -> bool:
        return not arg

print(Negator.neg(1))
print(Negator.neg(False))

相关问题 更多 >