[New-bugs-announce] [issue39679] functools: singledispatchmethod doesn't work with classmethod

Viktor Roytman report at bugs.python.org
Tue Feb 18 14:16:15 EST 2020


New submission from Viktor Roytman <viktor.roytman at gmail.com>:

I couldn't get the example given for the interaction between @singledispatchmethod and @classmethod to work https://docs.python.org/3/library/functools.html?highlight=singledispatch#functools.singledispatchmethod

    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
    
    
    if __name__ == "__main__":
        print(Negator.neg(0))
        print(Negator.neg(False))

Leads to

    $ python -m bad_classmethod_as_documented
    Traceback (most recent call last):
      File "/usr/lib/python3.8/runpy.py", line 193, in _run_module_as_main
        return _run_code(code, main_globals, None,
      File "/usr/lib/python3.8/runpy.py", line 86, in _run_code
        exec(code, run_globals)
      File "/home/viktor/scratch/bad_classmethod_as_documented.py", line 4, in <module>
        class Negator:
      File "/home/viktor/scratch/bad_classmethod_as_documented.py", line 12, in Negator
        def _(cls, arg: int):
      File "/usr/lib/python3.8/functools.py", line 906, in register
        return self.dispatcher.register(cls, func=method)
      File "/usr/lib/python3.8/functools.py", line 848, in register
        raise TypeError(
    TypeError: Invalid first argument to `register()`: <classmethod object at 0x7f37d1469070>. Use either `@register(some_class)` or plain `@register` on an annotated function.

Curiously, @staticmethod does work, but not as documented (don't decorate the actual implementations):

    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
    
    
    if __name__ == "__main__":
        print(Negator.neg(0))
        print(Negator.neg(False))

Leads to

    $ python -m good_staticmethod
    0
    True

Removing @classmethod from the implementation methods doesn't work, though

    Traceback (most recent call last):
      File "/usr/lib/python3.8/runpy.py", line 193, in _run_module_as_main
        return _run_code(code, main_globals, None,
      File "/usr/lib/python3.8/runpy.py", line 86, in _run_code
        exec(code, run_globals)
      File "/home/viktor/scratch/bad_classmethod_alternative.py", line 20, in <module>
        print(Negator.neg(0))
      File "/usr/lib/python3.8/functools.py", line 911, in _method
        return method.__get__(obj, cls)(*args, **kwargs)
    TypeError: _() missing 1 required positional argument: 'arg'

----------
components: Library (Lib)
messages: 362233
nosy: Viktor Roytman
priority: normal
severity: normal
status: open
title: functools: singledispatchmethod doesn't work with classmethod
type: behavior
versions: Python 3.8, Python 3.9

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue39679>
_______________________________________


More information about the New-bugs-announce mailing list