itertools.flatten()? and copying generators/iterators.
Francis Avila
francisgavila at yahoo.com
Wed Oct 29 20:47:54 EST 2003
"Peter Otten" <__peter__ at web.de> wrote in message
news:bnonsi$l5a$05$1 at news.t-online.com...
>
> def flatten_dict(s, isScalar):
> try:
> scalar = isScalar[s.__class__]
> except KeyError:
...
> t = s.__class__
Why doesn't the above fail (AttributeError) for classic classes?
...
> scalar = isScalar[t] = True
> else:
> scalar = isScalar[t] = False
This part I never would have thought to do. Clever!
...
> for flatten_dict(). So you get some speed up at the cost of uglier though
> still quite readable code and under the assumption that either all or no
> instances of a class are iterable.
That's not always a good assumption to make, if we want to decide whether to
iterate based upon some property of the object (which is actually how I
originally discovered I needed a "flatten").
Perhaps we can combine both conditions and caching optimizations?
def flatten_fastcond(s, isScalar, itercond=lambda o: None):
try:
scalar = isScalar[s.__class__]
except KeyError:
# If itercond has something to say about s, use *it*, and don't
# add the lookup to isScalar.
iterate = itercond(s)
if not iterate is None:
scalar = iterate
if not scalar:
s = iter(s)
else:
t = s.__class__
try:
s = iter(s)
except TypeError:
scalar = isScalar[t] = True
else:
scalar = isScalar[t] = False
if scalar:
yield s
else:
for elem in s:
for subelem in flatten_dict(elem, isScalar):
yield subelem
It's usually true that all instances of a given class are iterable or not,
and it's less inconvenient to add an entry to a dictionary than to write a
conditional test (also faster). If we move the itercond block above 'try',
we'll slow down this more common case, but speed things up if s is a
homogenous structure where itercond does all the work of deciding. There
are probably other things I could say against it if I thought about it, and
we're fast enough anyway.
As expected, given the same test tree (which doesn't exercise itercond), the
speed is about the same.
>python timeit.py -c -s"import flatten" "flatten.pro_fastcond()"
100 loops, best of 3: 6.29e+003 usec per loop
>python timeit.py -c -s"import flatten" "flatten.pro_dict()"
100 loops, best of 3: 6.29e+003 usec per loop
I'll make up some fancy tree later to test out itercond.
--
Francis Avila
More information about the Python-list
mailing list