Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
ddcb9818
Commit
ddcb9818
authored
May 09, 2015
by
Raymond Hettinger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #24018: Add a collections.Generator abstract base class.
parent
3e9f44d0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
145 additions
and
2 deletions
+145
-2
Doc/library/collections.abc.rst
Doc/library/collections.abc.rst
+10
-0
Lib/_collections_abc.py
Lib/_collections_abc.py
+60
-1
Lib/test/test_collections.py
Lib/test/test_collections.py
+72
-1
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Doc/library/collections.abc.rst
View file @
ddcb9818
...
...
@@ -40,6 +40,7 @@ ABC Inherits from Abstract Methods Mixin
:class:`Hashable` ``__hash__``
:class:`Iterable` ``__iter__``
:class:`Iterator` :class:`Iterable` ``__next__`` ``__iter__``
:class:`Generator` :class:`Iterator` ``send``, ``throw`` ``close``, ``__iter__``, ``__next__``
:class:`Sized` ``__len__``
:class:`Callable` ``__call__``
...
...
@@ -102,6 +103,15 @@ ABC Inherits from Abstract Methods Mixin
:meth:`~iterator.__next__` methods. See also the definition of
:term:`iterator`.
.. class:: Generator
ABC for generator classes that implement the protocol defined in
:pep:`342` that extends iterators with the :meth:`~generator.send`,
:meth:`~generator.throw` and :meth:`~generator.close` methods.
See also the definition of :term:`generator`.
.. versionadded:: 3.5
.. class:: Sequence
MutableSequence
...
...
Lib/_collections_abc.py
View file @
ddcb9818
...
...
@@ -9,7 +9,7 @@ Unit tests are in test_collections.
from
abc
import
ABCMeta
,
abstractmethod
import
sys
__all__
=
[
"Hashable"
,
"Iterable"
,
"Iterator"
,
__all__
=
[
"Hashable"
,
"Iterable"
,
"Iterator"
,
"Generator"
,
"Sized"
,
"Container"
,
"Callable"
,
"Set"
,
"MutableSet"
,
"Mapping"
,
"MutableMapping"
,
...
...
@@ -50,6 +50,7 @@ dict_values = type({}.values())
dict_items
=
type
({}.
items
())
## misc ##
mappingproxy
=
type
(
type
.
__dict__
)
generator
=
type
((
lambda
:
(
yield
))())
### ONE-TRICK PONIES ###
...
...
@@ -124,6 +125,64 @@ Iterator.register(str_iterator)
Iterator
.
register
(
tuple_iterator
)
Iterator
.
register
(
zip_iterator
)
class
Generator
(
Iterator
):
__slots__
=
()
def
__next__
(
self
):
"""Return the next item from the generator.
When exhausted, raise StopIteration.
"""
return
self
.
send
(
None
)
@
abstractmethod
def
send
(
self
,
value
):
"""Send a value into the generator.
Return next yielded value or raise StopIteration.
"""
raise
StopIteration
@
abstractmethod
def
throw
(
self
,
typ
,
val
=
None
,
tb
=
None
):
"""Raise an exception in the generator.
Return next yielded value or raise StopIteration.
"""
if
val
is
None
:
if
tb
is
None
:
raise
typ
val
=
typ
()
if
tb
is
not
None
:
val
=
val
.
with_traceback
(
tb
)
raise
val
def
close
(
self
):
"""Raise GeneratorExit inside generator.
"""
try
:
self
.
throw
(
GeneratorExit
)
except
(
GeneratorExit
,
StopIteration
):
pass
else
:
raise
RuntimeError
(
"generator ignored GeneratorExit"
)
@
classmethod
def
__subclasshook__
(
cls
,
C
):
if
cls
is
Generator
:
mro
=
C
.
__mro__
for
method
in
(
'__iter__'
,
'__next__'
,
'send'
,
'throw'
,
'close'
):
for
base
in
mro
:
if
method
in
base
.
__dict__
:
break
else
:
return
NotImplemented
return
True
return
NotImplemented
Generator
.
register
(
generator
)
class
Sized
(
metaclass
=
ABCMeta
):
__slots__
=
()
...
...
Lib/test/test_collections.py
View file @
ddcb9818
...
...
@@ -14,7 +14,7 @@ import sys
from
collections
import
UserDict
from
collections
import
ChainMap
from
collections
import
deque
from
collections.abc
import
Hashable
,
Iterable
,
Iterator
from
collections.abc
import
Hashable
,
Iterable
,
Iterator
,
Generator
from
collections.abc
import
Sized
,
Container
,
Callable
from
collections.abc
import
Set
,
MutableSet
from
collections.abc
import
Mapping
,
MutableMapping
,
KeysView
,
ItemsView
...
...
@@ -522,6 +522,77 @@ class TestOneTrickPonyABCs(ABCTestCase):
return
self
.
assertNotIsInstance
(
NextOnly
(),
Iterator
)
def
test_Generator
(
self
):
class
NonGen1
:
def
__iter__
(
self
):
return
self
def
__next__
(
self
):
return
None
def
close
(
self
):
pass
def
throw
(
self
,
typ
,
val
=
None
,
tb
=
None
):
pass
class
NonGen2
:
def
__iter__
(
self
):
return
self
def
__next__
(
self
):
return
None
def
close
(
self
):
pass
def
send
(
self
,
value
):
return
value
class
NonGen3
:
def
close
(
self
):
pass
def
send
(
self
,
value
):
return
value
def
throw
(
self
,
typ
,
val
=
None
,
tb
=
None
):
pass
non_samples
=
[
None
,
42
,
3.14
,
1j
,
b""
,
""
,
(),
[],
{},
set
(),
iter
(()),
iter
([]),
NonGen1
(),
NonGen2
(),
NonGen3
()]
for
x
in
non_samples
:
self
.
assertNotIsInstance
(
x
,
Generator
)
self
.
assertFalse
(
issubclass
(
type
(
x
),
Generator
),
repr
(
type
(
x
)))
class
Gen
:
def
__iter__
(
self
):
return
self
def
__next__
(
self
):
return
None
def
close
(
self
):
pass
def
send
(
self
,
value
):
return
value
def
throw
(
self
,
typ
,
val
=
None
,
tb
=
None
):
pass
class
MinimalGen
(
Generator
):
def
send
(
self
,
value
):
return
value
def
throw
(
self
,
typ
,
val
=
None
,
tb
=
None
):
super
().
throw
(
typ
,
val
,
tb
)
def
gen
():
yield
1
samples
=
[
gen
(),
(
lambda
:
(
yield
))(),
Gen
(),
MinimalGen
()]
for
x
in
samples
:
self
.
assertIsInstance
(
x
,
Iterator
)
self
.
assertIsInstance
(
x
,
Generator
)
self
.
assertTrue
(
issubclass
(
type
(
x
),
Generator
),
repr
(
type
(
x
)))
self
.
validate_abstract_methods
(
Generator
,
'send'
,
'throw'
)
# mixin tests
mgen
=
MinimalGen
()
self
.
assertIs
(
mgen
,
iter
(
mgen
))
self
.
assertIs
(
mgen
.
send
(
None
),
next
(
mgen
))
self
.
assertEqual
(
2
,
mgen
.
send
(
2
))
self
.
assertIsNone
(
mgen
.
close
())
self
.
assertRaises
(
ValueError
,
mgen
.
throw
,
ValueError
)
self
.
assertRaisesRegex
(
ValueError
,
"^huhu$"
,
mgen
.
throw
,
ValueError
,
ValueError
(
"huhu"
))
self
.
assertRaises
(
StopIteration
,
mgen
.
throw
,
StopIteration
())
class
FailOnClose
(
Generator
):
def
send
(
self
,
value
):
return
value
def
throw
(
self
,
*
args
):
raise
ValueError
self
.
assertRaises
(
ValueError
,
FailOnClose
().
close
)
class
IgnoreGeneratorExit
(
Generator
):
def
send
(
self
,
value
):
return
value
def
throw
(
self
,
*
args
):
pass
self
.
assertRaises
(
RuntimeError
,
IgnoreGeneratorExit
().
close
)
def
test_Sized
(
self
):
non_samples
=
[
None
,
42
,
3.14
,
1j
,
(
lambda
:
(
yield
))(),
...
...
Misc/NEWS
View file @
ddcb9818
...
...
@@ -39,6 +39,9 @@ Library
- Issue #24134: assertRaises(), assertRaisesRegex(), assertWarns() and
assertWarnsRegex() checks are not longer successful if the callable is None.
- Issue #24018: Add a collections.Generator abstract base class.
Contributed by Stefan Behnel.
- Issue #23880: Tkinter'
s
getint
()
and
getdouble
()
now
support
Tcl_Obj
.
Tkinter
's getdouble() now supports any numbers (in particular int).
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment