generator/coroutine terminology
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Mon Mar 16 04:36:50 EDT 2015
On Monday 16 March 2015 18:12, Marko Rauhamaa wrote:
> Steven D'Aprano <steve+comp.lang.python at pearwood.info>:
>
>> Marko Rauhamaa wrote:
>>> What features do generator iterators provide on top of generic
>>> iterators?
>>
>> The biggest difference is syntactic. Here's an iterator which returns a
>> never-ending sequence of squared numbers 1, 4, 9, 16, ...
>>
>> class Squares:
>> def __init__(self):
>> self.i = 0
>> def __next__(self):
>> self.i += 1
>> return self.i**2
>> def __iter__(self):
>> return self
>>
>>
>> Here's the same thing written as a generator:
>>
>> def squares():
>> i = 1
>> while True:
>> yield i**2
>> i += 1
>
> I was actually referring to the offered API. It still seems to me like
> all iterators could offer close(), send() and throw(). Why? To make all
> iterators drop-in replacements of each other.
How could these two iterators *possibly* be drop in replacements for each
other in any real body of code?
def inorder(tree):
for node in inorder(tree.left):
yield node.payload
yield tree.payload
for node in inorder(tree.right):
yield node.payload
def clean_up(collection, condition, cleaner=None):
if cleaner is None:
def cleaner(obj):
try:
obj.cache = {}
obj.ref = None
except Exception:
return False
return True
for i, item in enumerate(collection):
if condition(item):
flag = cleaner(item)
if flag:
yield Warn(MSG % (i, item))
You can't just substitute any random iterator for another, any more than you
can substitute any random two functions for each other.
Overly pure (in the comp sci theory sense) interfaces can be silly. Just
because the Soyez rocket and my nephew's tricycle are both instances of
Vehicle doesn't mean that I should be able to substitute one for the other.
OOP theory says they should. Reality says No Way.
Why should I, the class designer, be forced to offer send(), throw() and
close() methods on my iterators if I'm never going to use them as
coroutines? If I .send() into either of the generators above, its a
conceptual mistake and I should get an error. The fact that I don't is an
implementation detail, and one which hopefully will be fixed. I expect that
the interpreter can tell the difference between
yield spam
and
x = yield spam
and only allow send(), close() and throw() on generators which include the
second form. If it can't, then that's a limitation, not a feature to be
emulated.
> Then, you could also stop wondering what to call the thingy returned by
> a generator.
Apart from a few die-hards who are hoping for some sort of Académie
Française to define the One True meaning of words, most of us stopped
wondering what to call the thingy returned by a generator function years
ago. It's a generator, just like introspection of the object tells you.
> Why, it would be an iterator. You wouldn't then have any
> other use for a generator than the function that returns an iterator.
Lots of things are iterators. Doesn't make them generators.
> You could then decide if you want to reserve the name "generator" for
> functions that contain a yield statement (syntactic notion) or call any
> function returning an iterator a "generator" (semantic notion).
Why would you want the second? Do you have special names for {all functions
which return strings} and {all functions which return bools}?
Functions are normally described by their *form* or *purpose*, not their
return result, e.g. inner function, public function, callback function,
reentrant function, filter function.
--
Steve
More information about the Python-list
mailing list