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