# code by Martijn Pieters https://stackoverflow.com/a/23499088/1114975 from functools import singledispatch, wraps @singledispatch def depth(_, _level=1, _memo=None): return _level def _protect(f): """Protect against circular references""" @wraps(f) def wrapper(o, _level=1, _memo=None, **kwargs): _memo, id_ = _memo or set(), id(o) if id_ in _memo: return _level _memo.add(id_) return f(o, _level=_level, _memo=_memo, **kwargs) return wrapper def _protected_register(cls, func=None, _orig=depth.register): """Include the _protect decorator when registering""" if func is None and isinstance(cls, type): return lambda f: _orig(cls, _protect(f)) return _orig(cls, _protect(func)) if func is not None else _orig(_protect(cls)) depth.register = _protected_register @depth.register def _dict_depth(d: dict, _level=1, **kw): return max(depth(v, _level=_level + 1, **kw) for v in d.values())