Skip to content

Document that singledispatchmethod dispatches on the self argument when invoked from class level #143535

@johnslavik

Description

@johnslavik

In this usage of singledispatchmethod:

from functools import singledispatchmethod

class C:
    @singledispatchmethod
    def d(self, x):
        return "base!"

    @d.register(int)
    def _(self, x):
        return "int!"

print(C.d(C(), 1))

This is what I expected in the output:

int!

But instead this was printed out:

base!

singledispatch and singledispatchmethod don't analyze and adapt argument semantics to the registered callable type, which makes them very nice and simple.

_singledispatchmethod_get always dispatches on args[0] regardless of whether it's bound or unbound, and if it didn't, that would break descriptor support; this facet is crucial for staticmethod (and classmethod) dispatches to work:

from functools import singledispatchmethod

class C:
    @singledispatchmethod
    @staticmethod
    def d(x):
        return "base!"

    @d.register(int)
    @staticmethod
    def s(x):
        return "int!"
    
print(C.d(1))  # int!

Our tests rely on this and possibly millions of projects rely on this.

I think we could document this explicitly (and backport to 3.13 and 3.14).


Found this while working on GH-143465.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dirstdlibStandard Library Python modules in the Lib/ directory

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions