<br><br><div class="gmail_quote">On Fri, May 20, 2011 at 10:58 AM, Michael Tobis <span dir="ltr"><<a href="mailto:mtobis@gmail.com">mtobis@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
OK, but still.<br>
<br>
I have also faced this problem.<br>
<br>
Flattening nested lists which contain strings is an example.<br>
<br>
Because a string is an iterable, if we want a method that tolerates a<br>
single string or a list of strings, treating the single string the<br>
same as a list with one element, we have to be able to treat the<br>
string as a non-iterable. The question is what the most elegant way to<br>
do this is if we are building general purpose utility functions that<br>
we don;'t want to violate duck typing. I recall punting, but I also<br>
recall wondering the same thing.<br>
<br>
So, consider a routine that is intended to flatten a nested list. We<br>
want to write a recursive routine that takes [1,[2,3,[4,5],"fred"]] to<br>
[1,2,3,4,5,"fred"] and not to [1,2,3,4,5,"f","r","e","d"]. And even<br>
the latter is not as easy as you'd expect.<br>
<br>
It totally violated least surprise for me when I did something like<br>
<br>
>>> def atomprint(thing):<br>
... try:<br>
... for item in thing:<br>
... atomprint(item)<br>
... except TypeError:<br>
... print thing<br>
<br>
It works beautifully for lists of integers, floats, various other<br>
things. I felt satisfied and ever so pythonic. But it overflows the<br>
stack when you pass it a non-empty string!<br></blockquote></div><br><br>matplotlib.cbook defines "flatten" with a scalar customizable scalarp function to do what you want (the default returns True on non-iterables and strings). The module defines <br>
<br><br>def is_scalar_or_string(val):<br> return is_string_like(val) or not iterable(val)<br><br>def flatten(seq, scalarp=is_scalar_or_string):<br> """<br> this generator flattens nested containers such as<br>
<br> >>> l=( ('John', 'Hunter'), (1,23), [[[[42,(5,23)]]]])<br><br> so that<br><br> >>> for i in flatten(l): print i,<br> John Hunter 1 23 42 5 23<br><br> By: Composite of Holger Krekel and Luther Blissett<br>
From: <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/121294">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/121294</a><br> and Recipe 1.12 in cookbook<br> """<br> for item in seq:<br>
if scalarp(item): yield item<br> else:<br> for subitem in flatten(item, scalarp):<br> yield subitem<br><br><br><br>When applied to your example, it yields<br><br>In [49]: import matplotlib.cbook as cbook<br>
<br><br>In [51]: for row in cbook.flatten ([1,[2,3,[4,5],"fred"]] ):<br> ....: print row<br> ....:<br> ....:<br>1<br>2<br>3<br>4<br>5<br>fred<br><br><br>