Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is generator.throw() good for?

PEP 342 (Coroutines via Enhanced Generators) added a throw() method to generator objects, which allows the caller to raise an exception inside the generator (as if it was thrown by the yield expression).

I am wondering what the use cases for this feature are.

like image 898
NikiC Avatar asked Jul 14 '12 16:07

NikiC


People also ask

What does the throw () method do to a generator?

With the throw() method the caller can signal to the generator that there is an abnormal situation that has to be corrected.) If the generator can raise an exception, intercepted by the caller, the reverse should also be possible.

What is the advantage of generator function in Python?

Generators allow you to create iterators in a very pythonic manner. Iterators allow lazy evaluation, only generating the next element of an iterable object when requested. This is useful for very large data sets. Iterators and generators can only be iterated over once.

Why generators are faster Python?

A generator is better in performance because it doesn't hold the values at all. If the generator had a lot of values that needed to convert to that list then you lose the performance in terms of it will put all of those values into memory.

What is a generator function in Python?

Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python. Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).


1 Answers

Let's say I use a generator to handle adding information to a database; I use this to store network-received information, and by using a generator I can do this efficiently whenever I actually receive data, and do other things otherwise.

So, my generator first opens a database connection, and every time you send it something, it'll add a row:

def add_to_database(connection_string):     db = mydatabaselibrary.connect(connection_string)     cursor = db.cursor()     while True:         row = yield         cursor.execute('INSERT INTO mytable VALUES(?, ?, ?)', row) 

That is all fine and well; every time I .send() my data it'll insert a row.

But what if my database is transactional? How do I signal this generator when to commit the data to the database? And when to abort the transaction? Moreover, it is holding an open connection to the database, maybe I sometimes want it to close that connection to reclaim resources.

This is where the .throw() method comes in; with .throw() I can raise exceptions in that method to signal certain circumstances:

def add_to_database(connection_string):     db = mydatabaselibrary.connect(connection_string)     cursor = db.cursor()     try:         while True:             try:                 row = yield                 cursor.execute('INSERT INTO mytable VALUES(?, ?, ?)', row)             except CommitException:                 cursor.execute('COMMIT')             except AbortException:                 cursor.execute('ABORT')     finally:         cursor.execute('ABORT')         db.close() 

The .close() method on a generator does essentially the same thing; it uses the GeneratorExit exception combined with .throw() to close a running generator.

All this is an important underpinning of how coroutines work; coroutines are essentially generators, together with some additional syntax to make writing a coroutine easier and clearer. But under the hood they are still built on the same yielding, and sending. And when you are running multiple coroutines in parallel, you need a way to cleanly exit those coroutines if one of them has failed, just to name an example.

like image 147
Martijn Pieters Avatar answered Sep 21 '22 10:09

Martijn Pieters