Python-3.2 coroutine: AttributeError: 'generator' object has no attribute 'next'
Question:
Quoting from Python Essential Reference, by David Beazley, page 20:
Normally, functions operate on a single set of input arguments. However, a function can also be written to operate as a task that processes a sequence of inputs sent to it. This type of function is known as a coroutine and is created by using the yield
statement as an expression (yield) as shown in this example:
def print_matches(matchtext):
print "Looking for", matchtext
while True:
line = (yield) # Get a line of text
if matchtext in line:
print line
To use this function, you first call it, advance it to the first (yield), and then start sending data to it using send()
. For example:
>>> matcher = print_matches("python")
>>> matcher.next() # Advance to the first (yield)
Looking for python
>>> matcher.send("Hello World")
>>> matcher.send("python is cool")
python is cool
>>> matcher.send("yow!")
>>> matcher.close() # Done with the matcher function call
Based on that information, I wrote this code:
#!/usr/bin/python3.2
import sys
def match_text(pattern):
line = (yield)
if pattern in line:
print(line)
x = match_text('apple')
x.next()
for line in input('>>>> '):
if x.send(line):
print(line)
x.close()
But I get an error message like:
Traceback (most recent call last):
File "xxx", line 9, in <module>
matcher.next() # Advance to the first (yield)
AttributeError: 'generator' object has no attribute 'next'
Why doesn’t this code (or the code from the book, for that matter) work in Python 3.2? It seems that what is supposed to be a coroutine, is treated as a generator instead – why? What is going on here?
Answers:
You’re getting thrown off by the error message; type-wise, Python doesn’t make a distinction – you can .send
to anything that uses yield
, even if it doesn’t do anything with the sent value internally.
In 3.x, there is no longer a .next
method attached to these; instead, use the built-in free function next
:
next(matcher)
In the case you find yourself patching somebody’s code, it seems that the built-in python3 next() function calls the iterator’s next() function, so you may be able to find/replace somebody’s python2 .next(
with the python3-tolerable .__next__(
as I just did to make portions of the primefac module work in python3 (among other trivial changes).
Here’s the reference:
next(iterator[, default])
Retrieve the next item from the iterator by calling its next()
method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
For python version 3.2 the syntax for the next()
in-built function should be matcher.__next__()
or next(matcher)
.
Quoting from Python Essential Reference, by David Beazley, page 20:
Normally, functions operate on a single set of input arguments. However, a function can also be written to operate as a task that processes a sequence of inputs sent to it. This type of function is known as a coroutine and is created by using the
yield
statement as an expression (yield) as shown in this example:
def print_matches(matchtext):
print "Looking for", matchtext
while True:
line = (yield) # Get a line of text
if matchtext in line:
print line
To use this function, you first call it, advance it to the first (yield), and then start sending data to it using
send()
. For example:
>>> matcher = print_matches("python")
>>> matcher.next() # Advance to the first (yield)
Looking for python
>>> matcher.send("Hello World")
>>> matcher.send("python is cool")
python is cool
>>> matcher.send("yow!")
>>> matcher.close() # Done with the matcher function call
Based on that information, I wrote this code:
#!/usr/bin/python3.2
import sys
def match_text(pattern):
line = (yield)
if pattern in line:
print(line)
x = match_text('apple')
x.next()
for line in input('>>>> '):
if x.send(line):
print(line)
x.close()
But I get an error message like:
Traceback (most recent call last):
File "xxx", line 9, in <module>
matcher.next() # Advance to the first (yield)
AttributeError: 'generator' object has no attribute 'next'
Why doesn’t this code (or the code from the book, for that matter) work in Python 3.2? It seems that what is supposed to be a coroutine, is treated as a generator instead – why? What is going on here?
You’re getting thrown off by the error message; type-wise, Python doesn’t make a distinction – you can .send
to anything that uses yield
, even if it doesn’t do anything with the sent value internally.
In 3.x, there is no longer a .next
method attached to these; instead, use the built-in free function next
:
next(matcher)
In the case you find yourself patching somebody’s code, it seems that the built-in python3 next() function calls the iterator’s next() function, so you may be able to find/replace somebody’s python2 .next(
with the python3-tolerable .__next__(
as I just did to make portions of the primefac module work in python3 (among other trivial changes).
Here’s the reference:
next(iterator[, default])
Retrieve the next item from the iterator by calling its next()
method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
For python version 3.2 the syntax for the next()
in-built function should be matcher.__next__()
or next(matcher)
.