Chanelling Guido - dict subclasses
Peter Otten
__peter__ at web.de
Wed Jan 15 13:35:51 EST 2014
John Ladasky wrote:
> On Wednesday, January 15, 2014 12:40:33 AM UTC-8, Peter Otten wrote:
>> Personally I feel dirty whenever I write Python code that defeats duck-
>> typing -- so I would not /recommend/ any isinstance() check.
>
> While I am inclined to agree, I have yet to see a solution to the problem
> of flattening nested lists/tuples which avoids isinstance(). If anyone
> has written one, I would like to see it, and consider its merits.
Well, you should always be able to find some property that discriminates
what you want to treat as sequences from what you want to treat as atoms.
(flatten() Adapted from a nine-year-old post by Nick Craig-Wood
<https://mail.python.org/pipermail/python-list/2004-December/288112.html>)
>>> def flatten(items, check):
... if check(items):
... for item in items:
... yield from flatten(item, check)
... else:
... yield items
...
>>> items = [1, 2, (3, 4), [5, [6, (7,)]]]
>>> print(list(flatten(items, check=lambda o: hasattr(o, "sort"))))
[1, 2, (3, 4), 5, 6, (7,)]
>>> print(list(flatten(items, check=lambda o: hasattr(o, "count"))))
[1, 2, 3, 4, 5, 6, 7]
The approach can of course break
>>> items = ["foo", 1, 2, (3, 4), [5, [6, (7,)]]]
>>> print(list(flatten(items, check=lambda o: hasattr(o, "count"))))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 4, in flatten
File "<stdin>", line 2, in flatten
RuntimeError: maximum recursion depth exceeded
and I'm the first to admit that the fix below looks really odd:
>>> print(list(flatten(items, check=lambda o: hasattr(o, "count") and not
hasattr(o, "split"))))
['foo', 1, 2, 3, 4, 5, 6, 7]
In fact all of the following examples look more natural...
>>> print(list(flatten(items, check=lambda o: isinstance(o, list))))
['foo', 1, 2, (3, 4), 5, 6, (7,)]
>>> print(list(flatten(items, check=lambda o: isinstance(o, (list,
tuple)))))
['foo', 1, 2, 3, 4, 5, 6, 7]
>>> print(list(flatten(items, check=lambda o: isinstance(o, (list, tuple))
or (isinstance(o, str) and len(o) > 1))))
['f', 'o', 'o', 1, 2, 3, 4, 5, 6, 7]
... than the duck-typed variants because it doesn't matter for the problem
of flattening whether an object can be sorted or not. But in a real-world
application the "atoms" are more likely to have something in common that is
required for the problem at hand, and the check for it with
def check(obj):
return not (obj is an atom) # pseudo-code
may look more plausible.
More information about the Python-list
mailing list