def deep_type(obj, depth = None, max_sample = None, get_type = None):
    """Tries to construct a type for a given value. In contrast to type(...),
    deep_type does its best to fit structured types from typing as close as
    possible to the given value.
    E.g. deep_type((1, 2, 'a')) will return Tuple[int, int, str] rather than
    just tuple.
    Supports various types from typing, but not yet all.
    Also detects nesting up to given depth (uses pytypes.default_typecheck_depth
    if no value is given).
    If a value for max_sample is given, this number of elements is probed
    from lists, sets and dictionaries to determine the element type. By default,
    all elements are probed. If there are fewer elements than max_sample, all
    existing elements are probed.
    Optionally, a custom get_type function can be provided to further
    customize how types are resolved. By default it uses type function.
    """
    return _deep_type(obj, [], 0, depth, max_sample, get_type)
Tries to construct a type for a given value. In contrast to type(...),
    deep_type does its best to fit structured types from typing as close as
    possible to the given value.
    E.g. deep_type((1, 2, 'a')) will return Tuple[int, int, str] rather than
    just tuple.
    Supports various types from typing, but not yet all.
    Also detects nesting up to given depth (uses pytypes.default_typecheck_depth
    if no value is given).
    If a value for max_sample is given, this number of elements is probed
    from lists, sets and dictionaries to determine the element type. By default,
    all elements are probed. If there are fewer elements than max_sample, all
    existing elements are probed.
    Optionally, a custom get_type function can be provided to further
    customize how types are resolved. By default it uses type function.