You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Defining iterator in a separate class no longer works in 3.13 #128161
@ronaldoussoren You're right, and this code is definitely doing something weird, but it works in 3.12: example.py:
Right, the code from the OP is broken according to the data model, but we still did a change that's not backward compatible. I'm not deep enough into this to fully understand the ramifications.
The exact example worked in the CPython implementation of 3.12, but that may be an accident, as it should not have by the language definition. It might have already failed in 3.12 in other implementations. In any case, adding the following exposes the defect in list2iterable even in 3.12.
target2 = iter(target) # A list2iterator object
target3 = iter(target2) # Fails in 3.12.8
# TypeError: 'list2iterator' object is not iterable
If there is still a question about changing anything, Guido might remember the original design discussions.
I think we should decide what to do with this issue.
FYI, on current CPython 3.12 branch this code snippet works, but on 3.13, 3.14 and main branches it doesn't.
And maybe it's reasonable to do some changes in docs?
Some clear mention about generator expressions like (x for x in None), for example.
They aren't correct in Python 3.13.3 and before, an exception will be raised on this expression in code.
But on current 3.13 branch this code is correct.
Maybe it's better to remove all related changes in 3.13 branch?
And have exactly the same behavior as on 3.12?
Current title: "Defining iterator in a separate class no longer works in 3.13"
Suggested new title: "Iterator without __iter__ no longer works in 3.13.1"
Details:
If I understand correctly, the iterator being defined in a separate class isn't really relevant; what's very relevant is that it doesn't have an __iter__ member function
it's significant that the version in which this broke is minor release 3.13.1, not 3.13 (I observe the example code succeeds in 3.13.0)
The title and text of committed #132351 seems to imply that maybe it fixes this, i.e. reverts the behavior to pre-3.13.1 in which the example code works (because the generated bytcode has no redundant GET_ITER on something already known to be an iterator).
Is that correct?
That would make me very happy, since I would very much like to go back to happily ignoring the IMO ill-advised "requirement" that iterators be iterable (in fact it is my hope that some day that requirement might be officially removed, for a brighter less-confusing future in which Iterator and Iterable are two clearly distinct non-overlapping concepts).
And maybe it's reasonable to do some changes in docs?
Some clear mention about generator expressions like (x for x in None), for example.
They aren't correct in Python 3.13.3 and before, an exception will be raised on this expression in code.
But on current 3.13 branch this code is correct.
(Unfortunately I don't currently have anything higher than 3.13.0 to try this out on...)
In 3.13.0 I see that (x for x in None) throws TypeError: 'NoneType' object is not iterable which seems reasonable to me.
Are you saying that, in later versions, it returns something instead of throwing, and that it's correct? Why?
The title and text of committed #132351 seems to imply that maybe it fixes this, i.e. reverts the behavior to pre-3.13.1 in which the example code works (because the generated bytcode has no redundant GET_ITER on something already known to be an iterator).
This is because of changes in bytecode.
You can see two GET_ITER bytecodes for list comprehension here.
Suggested new title: "Iterator without __iter__ no longer works in 3.13.1"
It sounds reasonable for me. Although, this is not the only change.
(Unfortunately I don't currently have anything higher than 3.13.0 to try this out on...)
In 3.13.0 I see that (x for x in None) throws TypeError: 'NoneType' object is not iterable which seems reasonable to me. Are you saying that, in later versions, it returns something instead of throwing, and that it's correct? Why?
Yes, on current main, 3.14 and 3.13 branches we can see the following result:
Python 3.13.4 (main, Jun 4 2025, 17:14:13) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from test_iter import list2
>>> X=list2([1,2,3])
>>> [x for x in X]
[1, 2, 3]
But in 3.14.0b2 it sill does not work.
However it could be reintroduced again, related issue #135171 and fix #135225
If there's a decision how this should work, do we need some additional tests to make the behavior stable?
cc: @picnixz@markshannon
Whatever we decide on the main branch, you're better off adding an __iter__ method returning self to your iterator. There's no guarantee that this will always work in CPython or other implementations.
Activity
Eclips4 commentedon Dec 21, 2024
cc @efimov-mikhail @markshannon @JelleZijlstra
ronaldoussoren commentedon Dec 21, 2024
https://docs.python.org/3/library/stdtypes.html#iterator-types says that iterators must also implement
__iter__(returningself). That's a long standing requirement on iterators, and not one introduced in 3.13.antonio-rojas commentedon Dec 21, 2024
Alright, thanks
Eclips4 commentedon Dec 22, 2024
@ronaldoussoren You're right, and this code is definitely doing something weird, but it works in 3.12:
example.py:
3.12.8:
3.13.1:
Though it probably shouldn't work, it is definitely a regression.
Bytecode for
[x for x in y]3.12.8:3.13.1:
ronaldoussoren commentedon Dec 22, 2024
Right, the code from the OP is broken according to the data model, but we still did a change that's not backward compatible. I'm not deep enough into this to fully understand the ramifications.
efimov-mikhail commentedon Dec 22, 2024
This behavior change is a direct consequence of change in bytecode generation in my PR. I don't think this is a bug.
terryjreedy commentedon Dec 22, 2024
The exact example worked in the CPython implementation of 3.12, but that may be an accident, as it should not have by the language definition. It might have already failed in 3.12 in other implementations. In any case, adding the following exposes the defect in list2iterable even in 3.12.
If there is still a question about changing anything, Guido might remember the original design discussions.
pochmann3 commentedon Dec 23, 2024
Relevant bit from glossary: iterator:
7 remaining items
Adding a __iter__ method to skia.Iter
efimov-mikhail commentedon May 26, 2025
I think we should decide what to do with this issue.
FYI, on current CPython 3.12 branch this code snippet works, but on 3.13, 3.14 and main branches it doesn't.
@picnixz @Eclips4 @markshannon
Basically, there are two ways which I can see as reliable:
And some links on related issues and PRs:
#125038
#125178
#132351
efimov-mikhail commentedon May 26, 2025
And maybe it's reasonable to do some changes in docs?
Some clear mention about generator expressions like
(x for x in None), for example.They aren't correct in Python 3.13.3 and before, an exception will be raised on this expression in code.
But on current 3.13 branch this code is correct.
Maybe it's better to remove all related changes in 3.13 branch?
And have exactly the same behavior as on 3.12?
@hugovk @terryjreedy @JelleZijlstra
donhatch commentedon May 27, 2025
The issue title could perhaps be improved.
Current title: "Defining iterator in a separate class no longer works in 3.13"
Suggested new title: "Iterator without
__iter__no longer works in 3.13.1"Details:
__iter__member functiondonhatch commentedon May 27, 2025
The title and text of committed #132351 seems to imply that maybe it fixes this, i.e. reverts the behavior to pre-3.13.1 in which the example code works (because the generated bytcode has no redundant GET_ITER on something already known to be an iterator).
Is that correct?
That would make me very happy, since I would very much like to go back to happily ignoring the IMO ill-advised "requirement" that iterators be iterable (in fact it is my hope that some day that requirement might be officially removed, for a brighter less-confusing future in which Iterator and Iterable are two clearly distinct non-overlapping concepts).
donhatch commentedon May 27, 2025
@efimov-mikhail wrote:
(Unfortunately I don't currently have anything higher than 3.13.0 to try this out on...)
In 3.13.0 I see that
(x for x in None)throwsTypeError: 'NoneType' object is not iterablewhich seems reasonable to me.Are you saying that, in later versions, it returns something instead of throwing, and that it's correct? Why?
efimov-mikhail commentedon May 27, 2025
No, this is not correct.
On current main branch
This is because of changes in bytecode.
You can see two
GET_ITERbytecodes for list comprehension here.It sounds reasonable for me. Although, this is not the only change.
Yes, on current main, 3.14 and 3.13 branches we can see the following result:
You can see some motivation here:
#125178 (comment)
#132351 (comment)
cc @markshannon @sobolevn
[3.14] GH-128161: Remove redundant GET_ITER from list comprehension c…
[3.14] pythonGH-128161: Remove redundant GET_ITER from list comprehen…
[3.13] gh-128161: Remove redundant GET_ITER from list comprehension c…
[3.13] GH-128161: Fix refleak introduced in GH-134788 (GH-134799)
Roman513 commentedon Jun 8, 2025
This is fixed in 3.13.4:
But in 3.14.0b2 it sill does not work.
However it could be reintroduced again, related issue #135171 and fix #135225
If there's a decision how this should work, do we need some additional tests to make the behavior stable?
cc: @picnixz @markshannon
serhiy-storchaka commentedon Jun 10, 2025
Whatever we decide on the
mainbranch, you're better off adding an__iter__method returningselfto your iterator. There's no guarantee that this will always work in CPython or other implementations.efimov-mikhail commentedon Jun 22, 2025
I've started related d.p.o. thread here: https://discuss.python.org/t/generator-expressions-behavior-with-non-iterable-objects/96329.