This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Viktor Roytman
Recipients Viktor Roytman
Date 2020-02-18.19:16:14
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1582053375.25.0.178240077179.issue39679@roundup.psfhosted.org>
In-reply-to
Content
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'
History
Date User Action Args
2020-02-18 19:16:15Viktor Roytmansetrecipients: + Viktor Roytman
2020-02-18 19:16:15Viktor Roytmansetmessageid: <1582053375.25.0.178240077179.issue39679@roundup.psfhosted.org>
2020-02-18 19:16:15Viktor Roytmanlinkissue39679 messages
2020-02-18 19:16:14Viktor Roytmancreate