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. -- https://mail.python.org/mailman/listinfo/python-list