Skip to content
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

Mandatory Iterator with "yield" #633

Closed
fcolas opened this issue Apr 13, 2015 · 3 comments · Fixed by #1137
Closed

Mandatory Iterator with "yield" #633

fcolas opened this issue Apr 13, 2015 · 3 comments · Fixed by #1137

Comments

@fcolas
Copy link

fcolas commented Apr 13, 2015

Is it intended that the use of yield mandates the return type Iterator?
For example, if I want the squares of numbers:

def get_squares(n: int) -> Iterable[int]:
    return [i**2 for i in range(n)]

I cannot reimplement it as an iterator:

def get_squares(n: int) -> Iterable[int]:
    for i in range(n):
        yield i**2

without getting Iterator function return type expected for "yield" (even if Iterator actually is a subclass of Iterable).

However, it works with yield from:

def get_squares(n: int) -> Iterable[int]:
    yield from (i**2 for i in range(n))

What is the reasoning?

@rockneurotiko
Copy link
Contributor

Hi!

Like you say, 'yield from' check the return type and allow it if it's a subtype of 'Iterable' like you can see here:
https://github.com/JukkaL/mypy/blob/master/mypy/checker.py#L1384

The 'yield' word only allows 'Iterator' like you can see here:
https://github.com/JukkaL/mypy/blob/master/mypy/checker.py#L1357

Actually, yield and yield from, explained in the PEPs (225 and 380), return an Iterator (because both have a next function).

So, I think that the change should be change 'yield from' to only allow an Iterator as return type more than let 'yield' allow Iterable subclass.

@fcolas
Copy link
Author

fcolas commented Apr 13, 2015

But the thing is that Iterator is already an Iterable:

>>> import typing
>>> issubclass(typing.Iterator, typing.Iterable)
True

In the same way that my first example returns a List which is a subtype of Iterable, I'd expect my function to be correctly typed if I advertise an Iterable implemented as an Iterator. What am I missing?

@rockneurotiko
Copy link
Contributor

Yes, it's a subclass, and I've rediscovered why I wrote the 'yield from' support to allow Iterable subtype.

>>> def a():
        yield 1
        yield 2
        yield 3

>>> b = a()
>>> dir(b)
[..., '__iter__', ... '__next__',...]   # wrapped
>>> def a():
         yield from [1,2,3]

>>> b = a()
>>> dir(b)
[..., '__iter__', ...,  '__next__',...]  # wrapped

Both, 'yield' and 'yield from' have next (iterator) and iter (iterable), so, changing whan I've said in my previous comment, seems correct to allow iterable subtypes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants