Hi! First a bit of context.
Yesterday I spent a lot of time debugging the following method in a rather slim database abstraction layer we've developed: ,---- | def selectColumn(self, table, column, where={}, order_by=[], group_by=[]): | """Performs a SQL select query returning a single column | | The column is returned as a list. An exception is thrown if the | result is not a single column.""" | query = build_select(table, [column], where, order_by, group_by) | result = DBResult(self.rawQuery(query)) | if result.colcount != 1: | raise QueryError("Query must return exactly one column", query) | for row in result.fetchAllRowsAsList(): | yield row[0] `---- I'd just rewritten the method as a generator rather than returning a list of results. The following test then failed: ,---- | def testSelectColumnMultipleColumns(self): | res = self.fdb.selectColumn('db3ut1', ['c1', 'c2'], | {'c1':(1, 2)}, order_by='c1') | self.assertRaises(db3.QueryError, self.fdb.selectColumn, | 'db3ut1', ['c1', 'c2'], {'c1':(1, 2)}, order_by='c1') `---- I expected this to raise a QueryError due to the result.colcount != 1 constraint being violated (as was the case before), but that isn't the case. The constraint it not violated until I get the first result from the generator. Now to the main point. When a generator function is run, it immediately returns a generator, and it does not run any code inside the generator. Not until generator.next() is called is any code inside the generator executed, giving it traditional lazy evaluation semantics. Why don't generators follow the usual eager evaluation semantics of Python and immediately execute up until right before the first yield instead? Giving generators special case semantics for no good reason is a really bad idea, so I'm very curious if there is a good reason for it being this way. With the current semantics it means that errors can pop up at unexpected times rather than the code failing fast. Martin -- http://mail.python.org/mailman/listinfo/python-list