-
-
Notifications
You must be signed in to change notification settings - Fork 30.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
singledispatch on arguments that are themselves types/classes #100623
Comments
For anyone who needs/wants this earlier, I've created a standalone package which is just |
I also maintain a separate similar library called To sum up the long discussion we had:
So, I am strongly -1 on this. Sorry! |
@sobolevn Thanks for the detailed response! I think I agree with the outcome, but for completeness's sake, here are replies to every one of your points anyway - feel free to skip ahead to the last one which to me is the crux of the matter.
You mean from the user's side or the implementation side? From the user's side, I think it's quite intuitive as long as we're using annotations, because
Such as? 🤔
That is a good point and to be honest I can't think of a keyword that would transport the meaning of registering a function for type arguments rather than instance arguments... Something like
Hmm, not sure that has to be the case necessarily.
Perhaps, but as you've pointed out in https://sobolevn.me/2021/06/typeclasses-in-python#better-typing yourself, Mypy already can't handle a lot of
The 2nd option from your example got me thinking: All |
@sobolevn But by the way, in |
I had a similar feature idea some time ago. I must admit that whenever I had needed to make a my_dispatch = singledispatch(default_case_function)
def my_function(cls, *args, **kwargs):
return my_dispatch.dispatch(cls)(cls, *args, **kwargs)
my_function.register = my_dispatch.register No doubts that it's a bit of a workaround, and it works for me. But being honest, the presented idea of |
Given the discussion both here and on discuss.python.org, looks like this won't make it in, at least not right now, so I'll go ahead and close both this issue and the PR. @bswck Brilliant, I didn't even realize |
@smheidrich I've implemented your idea. https://github.com/bswck/class_singledispatch |
Was looking for similar functionality recently and had success with the following hack. It instantiates a dummy object that returns the specified class when the import functools
import numbers
def classdispatch(func):
func = functools.singledispatch(func)
def _inner(cls, *args, **kwargs):
class Dummy:
def __getattribute__(self, key):
return cls
return func(Dummy(), *args, **kwargs)
_inner.register = func.register
return _inner
@classdispatch
def do(cls):
raise NotImplementedError
@do.register(numbers.Number)
def _(cls):
print("a general number")
@do.register(int)
def _(cls):
print("an integer")
do(int) # an integer
do(float) # a general number |
Orr you can use https://github.com/bswck/class_singledispatch :P |
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: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 ofX
(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 bysingledispatch
, 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, sosingledispatch
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 functionfrom_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 withsingledispatch
, 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
The text was updated successfully, but these errors were encountered: