I want to propose adding switch cases to Python.
It would greatly clean up huge, ginourmous if branches
Plus, things like integers, could become jump tables, speeding things up.
I find that using a dict is perfectly appropriate for most cases. In some more advanced cases, match is also appropriate (though match is certainly not a drop-in replacement for a switch statement!)
Question, what is a match statement?
What would be the actual difference vs a match case?
About dicts being remplacements, sure for simple values, but with strict type checking they quickly become cumbersome to work with. Trying to type a dict with Callable values is an absolute nightmare
Moving to the general Help category as this already exists.
If you’re fighting against the type checker, something’s wrong. It should be serving you, it should not be the millstone around your neck. Perhaps don’t bother type checking it?
Progress has stalled, but it seems like you’d be interested in #88449.
dict[Hashable, Callable[[InputT1, InputT2, ...], ReturnType]]
That would be the simplest solution indeed but I’m the type of guy to have Ruff all + basedpyright all to type-check his test suite soo ![]()
and in any case a big “match-case like” situation like this is important enough to warrant strict typing no matter what IMO.
Yea that’s the simple case, very straightforward. Now what about diverging return types and/or argument types?
I would make a type variable or Protocol. Fair point if overloads don’t work very nicely with those.
At some point if the typing is difficult, I take the hint to simplify the code. The type signature should be determined by the thing that gets the value from the dict and calls it.
I appreciate Python code can easily get vastly more complicated than this, but that’s a force to oppose, not a trend to blithely go along with!
Really interesting. Isn’t possible to optimize an if-elif-else chain for such cases?
I use maps and I like them a lot.
I’ll do stuff like this all the time.
upid_map = {
0x00: ["No UPID", NoUpid, 0],
0x02: ["Type 0x02 is deprecated, use type 0x03", Upid, 8],
0x03: ["AdID", Adid, 12],
0x04: ["UMID", Umid, 32],
0x05: ["Type 0x05 is deprecated, use type 0x06", Isan, 8],
0x06: ["ISAN", Isan, 12],
0x07: ["TID", Tid, 12],
0x08: ["AiringID", Airid, 8],
0x0A: ["EIDR", Eidr, 12], }
if upid_type in upid_map:
upid_data= upid_map[upid_type]
mesg=upid_data[0]
the_upid =upid_data[1]() # this is a class
upid_max = upid_data[2]
TIP: Destructure that into separate variables.
if upid_type in upid_map:
mesg, cls, upid_max = upid_map[upid_type]
the_upid = cls()
And you can avoid the two-step check if you have defaults:
upid_map = {
..., ..., ..., # as above
"default": ["Unknown", NoUpid, 0],
}
mesg, cls, upid_max = upid_map.get(upid_type, upid_map["default"])
the_upid = cls()
(or have the default outside the map if you iterate over the map to get valid types). Very handy technique.
Some linters will complain about unpacking a list like this, but that’s trivially solved by using tuples or just disabling the lint rules
They probably should, since someone could accidentally append or pop something if you expose the map anywhere else.