from collections.abc import Iterable def traverse(list_or_value, callback): if isinstance(list_or_value, Iterable): for item in list_or_value: traverse(item, callback) else: callback(list_or_value) >>> traverse({"status": "ok"}, print) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse [Previous line repeated 989 more times] File "<stdin>", line 2, in traverse File "/usr/local/opt/python/libexec/bin/../../Frameworks/Python.framework/Versions/3.7/lib/python3.7/abc.py", line 139, in __instancecheck__ return _abc_instancecheck(cls, instance) RecursionError: maximum recursion depth exceeded in comparison Iterable that always returns an Iterable as an element! We can, of course, construct another example by creating a list and adding it to ourselves Razik Two, but how often do you find this in your code? And the line is Iterable infinite depth, which, under the cover of night, has penetrated right into your production.__contains__ method (the only method in the Abstract Base Container class), but then decide to add super-optimization for a special case — the collection. After all, you can just go over it and make a set ! import functools from typing import Collection, Container def faster_container(c: Container) -> Container: if isinstance(c, Collection): return set(c) return CachedContainer(c) class CachedContainer(object): def __init__(self, c: Container): self._contains = functools.lru_cache()(c.__contains__) def __contains__(self, stuff): return self._contains(stuff) >>> c = faster_container(othello_text) >>> "Have you pray'd to-night, Desdemona?" in c False __contains__ method __contains__ not consistent with the semantics of __iter__ and __len__ . >>> from collections.abc import Collection >>> issubclass(str, Collection) True __iter__ and __len__ believe that this is a collection of characters: >>> s = "foo" >>> len(s) 3 >>> list(s) ['f', 'o', 'o'] __contains__ thinks it's a collection of substrings! >>> "oo" in s True >>> "oo" in list(s) False str.__contains__ may seem strange in the context of __contains__ implementations of other standard types, this behavior is one of many little things that make Python so convenient as a scripting language; allowing to write on it fast and literary code. I would not suggest changing the behavior of this method, especially since we almost never use it to check for the presence of a single character in a string.__iter__ from the line, hide it behind some method like .chars() ? This would solve both of the indicated problems.Source: https://habr.com/ru/post/451252/
All Articles