def flatten( i ):
try:
i = i.__iter__()
while 1:
j = flatten( i.next() )
try:
while 1:
yield j.next()
except StopIteration:
pass
except AttributeError:
yield i
Probably you want to catch a TypeError instead of an AttributeError; objects may support the iterator protocol without defining an __iter__ method:
>>> class C: ... def __getitem__(self, index): ... if index > 3: ... raise IndexError(index) ... return index ... >>> list(iter(C())) [0, 1, 2, 3]
I would write your code as something like:
>>> def flatten(i):
... try:
... if isinstance(i, basestring):
... raise TypeError('strings are atomic')
... iterable = iter(i)
... except TypeError:
... yield i
... else:
... for item in iterable:
... for sub_item in flatten(item):
... yield sub_item
...
>>> list(flatten([['N','F'],['E'],['D']]))
['N', 'F', 'E', 'D']
>>> list(flatten([C(), 'A', 'B', ['C', C()]]))
[0, 1, 2, 3, 'A', 'B', 'C', 0, 1, 2, 3]Note that I special-case strings because, while strings support the iterator protocol, in this case we want to consider them 'atomic'. By catching the TypeError instead of an AttributeError, I can support old-style iterators as well.
Steve -- http://mail.python.org/mailman/listinfo/python-list
