Skip to content

singledispatch on arguments that are themselves types/classes #100623

@smheidrich

Description

@smheidrich

Feature or enhancement

It would be great if functools.singledispatch supported dispatching on arguments that are themselves types / classes. E.g. this should be possible:

from functools import singledispatch

@singledispatch
def describe(x) -> str:
  raise TypeError(f"no description for {repr(x)}")

@describe.register
def _(x: type[int]) -> str:
  return "the integer type"

print(describe(int))

Currently, it just raises an exception saying Invalid annotation for 'x'. type[int] is not a class..

Pitch

The main argument for this, in my opinion, is that it's something that one would simply expect to work, given that we can use type[X] to refer to a subtype of X (rather than an instance of such a type) in other typing-related contexts.

You could object that one could make the same argument for types like list[int] which are also not currently supported by singledispatch, but in that case, anyone will understand after 5 seconds of thinking about it that it would require costly checks to determine whether an argument is of that type or not, so singledispatch can't easily support it. Meanwhile, the check for whether a given type is a subtype of a "simple" type like a class is at least in principle no more costly than the analogous check for an instance of that type, so one would expect it to just work.

Use cases

Here is one use case for this I've encountered in real life:

I often use singledispatch to define generic functions that transform (data)class instances to various representations of the contained data, e.g. to_json(obj), to_terminal_output(obj), and so on, the advantage over methods being that the classes themselves can be kept relatively "clean" and not concerned with the details of all these different formats. Naturally the question arises whether we could have similar functions for the inverse case, e.g. a generic function from_json(...) that can transform JSON back into any (data)class instance for which an implementation is provided. But how should we tell the generic function which class we want to deserialize to? If we want to stick with singledispatch, the natural way would be to simply have the class itself as the first argument (from_json(klass, json: str)) which is not currently possible as demonstrated in the example above.

Previous discussion

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions