[Python-ideas] Proposal to extend PEP 484 (gradual typing) to support Python 2.7
Andrew Barnert
abarnert at yahoo.com
Wed Jan 20 19:54:53 EST 2016
On Wednesday, January 20, 2016 4:11 PM, Guido van Rossum <guido at python.org> wrote:
>On Wed, Jan 20, 2016 at 9:42 AM, Andrew Barnert via Python-ideas <python-ideas at python.org> wrote:
>
>On Jan 20, 2016, at 06:27, Agustín Herranz Cecilia <agustin.herranz at gmail.com> wrote:
>>>
>>> - GVR proposal includes some kind of syntactic sugar for function type comments (" # type: (t_arg1, t_arg2) -> t_ret "). I think it's good but this must be an alternative over typing module syntax (PEP484), not the preferred way (for people get used to typehints). Is this syntactic sugar compatible with generators? The type analyzers could be differentiate between a Callable and a Generator?
>>
>>I'm pretty sure Generator is not the type of a generator function, bit of a generator object. So to type a generator function, you just write `(int, int) -> Generator[int]`. Or, the long way, `Function[[int, int], Generator[int]]`.
>
>There is no 'Function' -- it existed in mypy before PEP 484 but was replaced by 'Callable'. And you don't annotate a function def with '-> Callable' (unless it returns another function).
Sorry about getting the `Function` from the initial proposal instead of the current PEP.
Anyway, I don't think the OP was suggesting that. If I interpreted his question right:
He was expecting that the comment `(int, int) -> int` was a way to annotate a function so it comes out as type `Callable[[int, int], int]`, which is correct. And he wanted to know how to instead write a comment for a generator function of type `GeneratorFunction[[int, int], int]`, and the answer is that you don't. There is no type needed for generator functions; they're just functions that return generators.
You're right that he doesn't need to know the actual type; you're never going to write that, you're just going to annotate the arguments and return value, or use the 2.x comment style:
def f(arg1: int, arg2: int) -> Iterator[int]
def f(arg1, arg2):
# type: (int, int) -> Iterator[int]
Either way, the type checker will determine that type of the function is `Callable[[int, int], Iterator[int]]`, and the only reason you'll ever care is if that type shows up in an error message.
>Regarding using Iterator[T] instead of Generator[..., ..., T], you are correct.
>
>Note that you *cannot* define a generator function as returning a *subclass* of Iterator/Generator;
But you could define it as returning the superclass `Iterable`, right? As I understand it, it's normal type variance, so any superclass will work; the only reason `Iterator` is special is that it happens to be simpler to specify than Generator and it's plausible that it isn't going to matter whether you've written a generator function or, say, a function that returns a list iterator.
> there is no way to have a generator function instantiate some other class as its return value.
If you really want that, you could always write a wrapper that forwards __next__, and a decorator that applies the wrapper. Can MyPy infer the type of the decorated function from the wrapped function and the decorator?
# Can I leave this annotation off? And get one specialized to the actual
# argument types of the wrapped function? That would be cool.
def my_iterating(func: Callable[Any, Iterator]) -> Callable[Any, MyIterator]
@wraps(func)
def wrapper(*args, **kw):
return MyIterator(func(*args, **kw))
return wrapper
@my_iterating
def foo() -> Iterator[int]:
yield
x = foo()
x.bar()
More information about the Python-ideas
mailing list