It is perfectly possible in maybe 20-30 lines of code to write a decorator that adds runtime generics in a really easy to use way. [1] PEP 695 makes this quite convenient. Currently the biggest blocker for its usage is that type checkers don’t like it. Implementing the same thing for classes is a bit harder, but very much possible.
IMO runtime access not being possible shouldn’t be considered a problem if this feature, this feature not existing is a blocker for runtime access.
I can’t provide the code right now, I am on my phone ↩︎
Thanks for the comments and sorry I took so long to get to this.
Yeah I don’t entirely disagree with this sentiment though I do think it does have merit to stand on its own feet as outlined at the end.
Some of the examples from the PEP were taken from real world code this wasn’t one of these pieces of code though I don’t think it’s actually that unreasonable to see a case where this could come up
I’m curious if you’d be able to dig these up because they’d be useful for adding strength to the argument.
My main reasons for writing the PEP
Completely agree with Gudio’s point about the complexity of the types, I think this feeds into the next point nicely.
Symmetry with classes. I’ve had multiple people be surprised that this wasn’t already a feature. I think it is a logical change post PEP 585.
Prospect of runtime access. I know that this isn’t really brought up in the PEP though it is something I am working on, I did see this however as a large enough change that is should be separated from this PEP.
static typing asymmetry between functions and classes is a big pain point in general for our team (mostly data scientists). I would say, generally speaking: people love the benefits of having types, but they don’t like writing them because it’s “hard.” And a big reason it’s hard is that there are a lot of minor inconsistencies, where I have to tell people the equivalent of “oh, yeah, you can’t do it that way because of X - you need to do it like this” (which is always followed by writing 5 extra lines of something they’ve never seen before). Note: I’m not trying to convince any readers of this - if you’ve experienced it, I’m sure you’ll know what I’m talking about, but it’s beyond the scope of this discussion to walk through a bunch of concrete examples. Therefore: any concessions toward consistency (why can I do this with classes but not with functions - I thought Python had first class functions?), while they may seem minor in “functionality” benefit, are cumulatively major in making Python pleasant to use with static types.
giving access to this parameter at runtime seems like it would be a nice-to-have, and because I am in favor of this precisely because of the advantages of consistency, I would lean toward throwing it in. The thing that would be unpleasant is if we ended up with a situation where tools ended up requiring users to do both: e.g. my_foo = deserialize_obj[Foo](some_bytes, Foo) - i.e. passing the type as a function argument in addition to using the ‘standard’ annotation. That said, I am in favor of this also primarily as a concession toward consistency; I’ve not personally gotten to use cls.__orig_bases__ yet, so I can’t speak to the usability of the class side of things directly.
performance concerns of the added __getitem__ call, etc, really should not be relevant to this topic. The vast majority of real world use cases for this, I predict, will be in cases where very dynamic (and slow) code is running under the hood. The slowness from this form will be dwarfed by the slowness of whatever is actually being run. Furthermore, as has been pointed out, if there’s any need to run this inside a loop, it will be possible to construct the specialized version outside the loop and use it inside the loop.
This PEP doesn’t seem like a huge step forward, but the top two things Python static typing could use more of are:
consistency
expressivity
and this helps with both to a small degree.