PEP 342: Add more examples based on ideas stolen from an early version of
PEP 288. Also add some more explanation of the 'throw()' name, also stolen from PEP 288. :)
This commit is contained in:
parent
c97e46d034
commit
e149a9dcbc
85
pep-0342.txt
85
pep-0342.txt
|
@ -247,6 +247,18 @@ Specification: Exceptions and Cleanup
|
||||||
supplied, must be a valid Python traceback object, or a TypeError
|
supplied, must be a valid Python traceback object, or a TypeError
|
||||||
occurs.
|
occurs.
|
||||||
|
|
||||||
|
Note: The name of the throw() method was selected for several
|
||||||
|
reasons. Raise is a keyword and so cannot be used as a method
|
||||||
|
name. Unlike raise (which immediately raises an exception from the
|
||||||
|
current execution point), throw() first resumes the generator, and
|
||||||
|
only then raises the exception. The word throw is suggestive of
|
||||||
|
putting the exception in another location, and is already associated
|
||||||
|
with exceptions in other languages.
|
||||||
|
|
||||||
|
Alternative method names were considered: resolve(), signal(),
|
||||||
|
genraise(), raiseinto(), and flush(). None of these seem to fit
|
||||||
|
as well as throw().
|
||||||
|
|
||||||
New standard exception: GeneratorExit
|
New standard exception: GeneratorExit
|
||||||
|
|
||||||
A new standard exception is defined, GeneratorExit, inheriting
|
A new standard exception is defined, GeneratorExit, inheriting
|
||||||
|
@ -358,7 +370,76 @@ Open Issues
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
|
||||||
1. A simple co-routine scheduler or "trampoline" that lets
|
1. A simple "consumer" decorator that makes a generator function
|
||||||
|
automatically advance to its first yield point when initially
|
||||||
|
called:
|
||||||
|
|
||||||
|
def consumer(func):
|
||||||
|
def wrapper(*args,**kw):
|
||||||
|
gen = func(*args, **kw)
|
||||||
|
gen.next()
|
||||||
|
return gen
|
||||||
|
wrapper.__name__ = func.__name__
|
||||||
|
wrapper.__dict__ = func.__dict__
|
||||||
|
wrapper.__doc__ = func.__doc__
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
2. An example of using the "consumer" decorator to create a
|
||||||
|
"reverse generator" that receives images and creates thumbnail
|
||||||
|
pages, sending them on to another consumer. Functions like
|
||||||
|
this can be chained together to form efficient processing
|
||||||
|
pipelines of "consumers" that each can have complex internal
|
||||||
|
state:
|
||||||
|
|
||||||
|
@consumer
|
||||||
|
def thumbnail_pager(pagesize, thumbsize, destination):
|
||||||
|
while True:
|
||||||
|
page = new_image(pagesize)
|
||||||
|
rows, columns = pagesize / thumbsize
|
||||||
|
pending = False
|
||||||
|
try:
|
||||||
|
for row in xrange(rows):
|
||||||
|
for column in xrange(columns):
|
||||||
|
thumb = create_thumbnail((yield), thumbsize)
|
||||||
|
page.write(
|
||||||
|
thumb, col*thumbsize.x, row*thumbsize.y
|
||||||
|
)
|
||||||
|
pending = True
|
||||||
|
except GeneratorExit:
|
||||||
|
# close() was called, so flush any pending output
|
||||||
|
if pending:
|
||||||
|
destination.send(page)
|
||||||
|
|
||||||
|
# then close the downstream consumer, and exit
|
||||||
|
destination.close()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# we finished a page full of thumbnails, so send it
|
||||||
|
# downstream and keep on looping
|
||||||
|
destination.send(page)
|
||||||
|
|
||||||
|
@consumer
|
||||||
|
def jpeg_writer(dirname):
|
||||||
|
fileno = 1
|
||||||
|
while True:
|
||||||
|
filename = os.path.join(dirname,"page%04d.jpg" % fileno)
|
||||||
|
write_jpeg((yield), filename)
|
||||||
|
|
||||||
|
|
||||||
|
# Put them together to make a function that makes thumbnail
|
||||||
|
# pages from a list of images and other parameters.
|
||||||
|
#
|
||||||
|
def write_thumbnails(pagesize, thumbsize, images, output_dir):
|
||||||
|
pipeline = paginate(
|
||||||
|
pagesize, thumbsize, jpeg_writer(output_dir)
|
||||||
|
)
|
||||||
|
|
||||||
|
for image in images:
|
||||||
|
pipeline.send(image)
|
||||||
|
|
||||||
|
pipeline.close()
|
||||||
|
|
||||||
|
3. A simple co-routine scheduler or "trampoline" that lets
|
||||||
coroutines "call" other coroutines by yielding the coroutine
|
coroutines "call" other coroutines by yielding the coroutine
|
||||||
they wish to invoke. Any non-generator value yielded by
|
they wish to invoke. Any non-generator value yielded by
|
||||||
a coroutine is returned to the coroutine that "called" the
|
a coroutine is returned to the coroutine that "called" the
|
||||||
|
@ -437,7 +518,7 @@ Examples
|
||||||
|
|
||||||
self.queue.append(resume)
|
self.queue.append(resume)
|
||||||
|
|
||||||
2. A simple "echo" server, and code to run it using a trampoline
|
4. A simple "echo" server, and code to run it using a trampoline
|
||||||
(presumes the existence of "nonblocking_read",
|
(presumes the existence of "nonblocking_read",
|
||||||
"nonblocking_write", and other I/O coroutines, that e.g. raise
|
"nonblocking_write", and other I/O coroutines, that e.g. raise
|
||||||
ConnectionLost if the connection is closed):
|
ConnectionLost if the connection is closed):
|
||||||
|
|
Loading…
Reference in New Issue