-
-
Notifications
You must be signed in to change notification settings - Fork 117
Add a covariant Mapping
-like type
#5
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
Comments
Mapping
-like type
As I wrote in the original issue, I think this would be quite useful in addition to our tight protocols. Maybe we could have a look at the use of |
The proposal I made, was intended to be "as broad as possible, but without breaking covariance". In light of that, I should probably inherit from The reason I want a type that is "as broad as possible", has to do with usability. Tight protocols can, unfortunately, be cumbersome, in some situations, as long as we lack intersection types. A concrete (but perhaps silly) example of a function in need of annotation: def do_more_than_one_thing_with_a_mapping(mapping):
# The exact methods called on the mapping are unimportant.
# The salient detail is that there's more than one method being called.
return any(mapping.keys()), all(mapping.values()) And three ways of annotating it:
def silly_fn(mapping: SupportsKeys & SupportsItems) -> tuple[bool, bool]:
...
class SupportsKeysAndItems(SupportsKeys[KT_co], SupportsItems[VT_co], Protocol[KT_co, VT_co]):
# A full extra class definition, just to create an intersection type(!)
...
def silly_fn(mapping: SupportsKeysAndItems) -> tuple[bool, bool]:
...
def silly_fn(mapping: CovariantMappingLike) -> tuple[bool, bool]:
... My preference looks like: 1 > 3 > 2, so until we can have 1, I'd prefer having the option of 3 available when calling more than one method on the mapping. Not trying to say that narrow protocols are bad. They can be really useful when annotating simple functions. So I want them around. It's just that the syntax for composing them is so bad that I'd like someone else to do it for me, neatly hidden away in some library. |
I feel this is too rarely needed to add here. You can just define a protocol in your own code. |
The need to interact co-variantly with mapping keys seems pretty common to me. See:
This type can be used for every function that interacts with a mapping without looking up values, i.e. covering all "safe" use-cases of what's suggested in the issues mentioned above. That's a pretty good compromise solution IMO. The Mapping stubs in typeshed can also be defined based on this type, making for a neat simplification, and also isolates the part of the Mapping API that leads to invariance, which, I think, is a good idea. |
If we have to have it, maybe CovariantMapping? |
One objection to that name is that it can sound a bit like a subtype of Mapping. But in this case it's a supertype. Not sure how to convey that elegantly. |
I don't think you can get the perfect name, so I recommend not overthinking it. |
My main question is when would you choose covariant mapping vs mapping with a typevar for key? What's difference between, def foo(mapping: CovariantMapping[Hashable, Hashable]):
... vs HashableT = TypeVar('HashableT', bound=Hashable)
def foo(mapping: Mapping[HashableT, Hashable]):
... I occasionally use latter as a way to make an invariant type argument behave as if it were covariant. |
I have, and am using the same pattern. But it is both more verbose, and harder to understand for the reader. Given that most documentation for That is, for the inexperienced reader, seeing: |
I agree that the need for a mapping type that is covariant in its key does come up regularly, but a mapping protocol that doesn't implement I think a more useful "covariant in keys" mapping type would be one that does provide I think it's too late to make this change for |
Closing this following the policy to only include things that are in CPython or in a PEP. |
Is there an alternative location where these non-PEP, but generally usable types could be shared? |
We'll have to make a new package; I think @hauntsaninja is planning to do that. |
What
I want a new protocol added to
typing
ortyping_extensions
, expressing the aspects ofMapping
that are covariant with regards to the key type. That is, theMapping
type, but without the__getitem__
andget
methods.Something along the lines of:
Why
Mapping
s are often, in practice, treated in ways that make them covariant with regards to key. A specific example is laid out in a comment of mine found here: python/typing#445 (comment)The
Mapping
type, however, cannot be covariant w. regards to key, as it also implements methods that don't allow for it (__getitem__
andget
) to be covariant.This leaves me unable to express, in a simple and idiomatic way, that I intend to use a
Mapping
in a way that respects covariance.Being able to write:
would allow me to express what I'm after. It would allow me to express: "Give me a mapping, but I promise to not be looking up keys on it."
This, again, makes it possible to have narrower key types for my
Mapping
objects, as I can pass a narrowly typedMapping
tofoo
, without casting:I was prompted by @srittau to create this issue in python/typing#445 (comment)
The text was updated successfully, but these errors were encountered: