On 2007-07-25, Carsten Haese <carsten@uniqsy s.comwrote:
On Wed, 2007-07-25 at 19:26 +0000, Neil Cerutti wrote:
>Speaking of the iter builtin function, is there an example of the
>use of the optional sentinel object somewhere I could see?
>
Example 1: If you use a DB-API module that doesn't support direct cursor
iteration with "for row in cursor", you can simulate it this way:
>
for row in iter(cursor.fet chone, None):
# do something
>
Example 2: Reading a web page in chunks of 8kB:
>
f = urllib.urlopen( url)
for chunk in iter(lambda:f.r ead(8192), ""):
# do something
Ah! Thanks for the examples. That's much simpler than I was
imagining. It's also somewhat evil, but I suppose it conserves a
global name to do it that way.
On Wed, 2007-07-25 at 19:26 +0000, Neil Cerutti wrote:
>Speaking of the iter builtin function, is there an example of the
>use of the optional sentinel object somewhere I could see?
>
Example 1: If you use a DB-API module that doesn't support direct cursor
iteration with "for row in cursor", you can simulate it this way:
>
for row in iter(cursor.fet chone, None):
# do something
>
[...]
This would, of course, be a horribly inefficient way to handle a
database result with 1,500,000 rows. Calling fetchall() might also have
its issues. The happy medium is to use a series of calls to fetchmany(N)
with an appropriate value of N.
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
--------------- Asciimercial ------------------
Get on the web: Blog, lens and tag the Internet
Many services currently offer free registration
----------- Thank You for Reading -------------
The call to iter will fail for objects that don't support the
iterator protocol, and the call to next will fail for a
(hopefully large) subset of the objects that don't support the
sequence protocol.
This seems preferable to cluttering code with exception handling
and inspecting tracebacks. But it's still basically wrong, I
guess.
To repost my use case:
def deeply_mapped(f unc, iterable):
""" Recursively apply a function to every item in a iterable object,
recursively descending into items that are iterable. The result is an
iterator over the mapped values. Similar to the builtin map function, func
may be None, causing the items to returned unchanged.
"""
for item in iterable:
if is_iterable(ite m):
for it in deeply_mapped(f unc, item):
if func is None:
yield it
else:
yield func(it)
else:
if func is None:
yield item
else:
yield func(item)
--
Neil Cerutti
On Thu, 26 Jul 2007 15:02:39 +0000, Neil Cerutti wrote:
Based on the discussions in this thread (thanks all for your
thoughts), I'm settling for:
>
def is_iterable(obj ):
try:
iter(obj).next( )
return True
except TypeError:
return False
except KeyError:
return False
>
The call to iter will fail for objects that don't support the
iterator protocol, and the call to next will fail for a
(hopefully large) subset of the objects that don't support the
sequence protocol.
And the `next()` consumes an element if `obj` is not "re-iterable".
On 2007-07-26, George Sakkis <george.sakkis@ gmail.comwrote:
That's not the only problem; try a string element to see it
break too. More importantly, do you *always* want to handle
strings as iterables ?
>
The best general way to do what you're trying to is pass
is_iterable() as an optional argument with a sensible default,
but allow the user to pass a different one that is more
appropriate for the task at hand:
>
def is_iterable(obj ):
try: iter(obj)
except: return False
else: return True
def flatten(obj, is_iterable=is_ iterable):
That makes good sense.
Plus the subtly different way you composed is_iterable is clearer
than what I originally wrote. I haven't ever used a try with an
else.
if is_iterable(obj ):
for item in obj:
for flattened in flatten(item, is_iterable):
yield flattened
else:
yield obj
>
By the way, it's bad design to couple two distinct tasks:
flattening a (possibly nested) iterable and applying a function
to its elements. Once you have a flatten() function,
deeply_mapped is reduced down to itertools.imap.
I chose to implement deeply_mapped because it illustrated the
problem of trying to catch a TypeError exception when one might
be thrown by some other code. I agree with your opinion that it's
a design flaw, and most of my problems with the code were caused
by that flaw.
Comment