Skip to content

Conversation

@johnslavik
Copy link
Member

@johnslavik johnslavik commented Feb 8, 2026

Unbound methods (i.e. functions) become bound methods when regularly accessed as instance attributes. From the class level, the contract of Python is that the first argument to the call will be used as the conventional self and the call will execute directly (without creating a bound method in between). Following the contract, a natural expectation is that when generic methods are called as class attributes, the second argument will be used for dispatching, not the first (the conventional self).

To support descriptors like classmethod (that bind to something else than the instance), arguments are shifted by one even if __get__ method returns a method that is bound to a different object than the original self (_singledispatchmethod_get._obj). If one wants to receive that self in an arbitrary bound method as a regular argument, the workaround is easy: return a partial(bound method) to hack the check.

This is a low risk bugfix. The patch is meant to fix the following program:

class C:
   @singledispatchmethod
   def generic(self, x: object):
       return "generic"

   @generic.register
   def special(self, x: int):
       return "special"

assert C.generic(C(), 1) == "generic"  # should be "special"

@johnslavik johnslavik marked this pull request as ready for review February 9, 2026 01:23
@johnslavik
Copy link
Member Author

johnslavik commented Feb 9, 2026

@rhettinger, do you like this fix? Or do you like a documentation change more?
FWIW I don't recall this bug being reported in the past, but the fix looks cheap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant