[Python-ideas] Proposal: Use mypy syntax for function annotations
Andrew Barnert
abarnert at yahoo.com
Sun Aug 24 12:04:09 CEST 2014
On Aug 24, 2014, at 1:50, Steven D'Aprano <steve at pearwood.info> wrote:
> On Sun, Aug 24, 2014 at 10:00:32AM +0200, Georg Brandl wrote:
>> On 08/24/2014 07:54 AM, Greg Ewing wrote:
>>> Steven D'Aprano wrote:
>>>> I don't really understand what you're trying to say here, so I may be
>>>> misinterpreting you. I *think* that you're trying to say that for every
>>>> type in the standard library, and every class created by third parties
>>>> (including subclasses), the author will have to "declare" (in some
>>>> unknown sense) that it can be used for type annotations like MyList[T],
>>>> for some type T.
>>>
>>> I suppose the run-time incarnations of the type descriptions
>>> could be looser, but if you want to use them for static checking,
>>> the static checker is going to have to know what MyList[T] means
>>> in some detail (what effect the parameter has on the method
>>> types, etc.) The programmer will have to specify all that
>>> somehow.
>>>
>>> The way this is done in other languages with static type
>>> checking is to give the class declaration a parameter list.
>>> I was envisaging that the mypy type description syntax would have
>>> something equivalent. Not sure what form it would take, though.
>>
>> Exactly. Does mypy handle that? For example, for a custom mapping
>> type
>>
>> class Mapping(object):
>> def setitem(self, key, value):
>> ...
>>
>> how would one specify
>> a) that you can use Mapping[T1, T2] as a type annotation and
>> b) the type annotations for the "key" and "value" arguments?
>
> I'm not an expert on Mypy, but I think the answer is, you can't. In
> order for Mypy to recognise your Mapping as an actual mapping, you have
> to either inherit from dict or some other mapping which Mypy knows
> about, or from typing.Generic.
>
> http://mypy-lang.org/tutorial.html#genericclasses
>
>
> from typing import typevar, Generic
> T = typevar('T')
> class Mapping(Generic[T, T]):
> ...
>
>
> Now Mypy will know that your Mapping class should be considered a
> mapping from some type to another type, and you can use it:
No it doesn't, it just knows that it's a generic type, meaning that you can index it with types, and those types will be used to fill in the corresponding typevars on its methods.
Consider Tuple[int, str]. That isn't a mapping from int to str, it's a 2-element tuple whose first element is int and whose second is str. And I'm sure you can come up with other uses for generic types of two type parameters that aren't mappings.
This is exactly the same as in C++, ML and its descendants, and Java and its descendants.
For example:
class MyMapping(Generic[T, U]):
def __getitem__(self, key: T) -> U:
# ...
Now a function that takes a MyMapping[int, str] will bind T to int and U to str, so the type checker knows that the argument to __getitem__ is an int and the return value is a str.
And that still doesn't make it a Mapping. If collections.abc.Mapping (or typing.Mapping, if they're separate in the final version) is a Protocol, or otherwise implements structural matching, _that_ is what makes MyMapping a Mapping. And if if doesn't, then only inheriting or registering can make it a Mapping. Just like ABCs at runtime.
More information about the Python-ideas
mailing list