简体   繁体   中英

Python: how to display nested type information?

Does Python inclue a built-in type variant that will display nested type information, something like this?

>>> extended_type([()])
<class 'list' containg <class 'tuple'>>

No. Type hints and the typing module and PEP 585 provide a notation for this (namely list[tuple] or List[tuple] before Python 3.9), but these are only meant to be checked by an external type-checker like MyPy; there's no capability for checking it at runtime.

PEP 585 on Making isinstance(obj, list[str]) perform a runtime type check :

This functionality requires iterating over the collection which is a destructive operation in some of them. This functionality would have been useful, however implementing the type checker within Python that would deal with complex types, nested type checking, type variables, string forward references, and so on is out of scope for this PEP.

The type of a container's items are opaque to the type of the container itself. However, you can make your own for things that implement __iter__ :

def extended_type(x):
    types = set()
    if hasattr(x, "__iter__"):
        for item in x:
            if item == x:
                # prevent strings from infinitely recursing
                continue
            types.add(extended_type(item))
        contains = ""
        if len(types) > 0:
            contains = " containing " + ", ".join(types)
        return f"<class '{type(x).__name__}'{contains}>"
    return f"<class '{type(x).__name__}'>"

extended_type([(1, 2, 'a'), {1: 2}])
# "<class 'list' containing <class 'tuple' containing <class 'str'>, <class 'int'>>, <class 'dict' containing <class 'int'>>>"

@Aplet123 inspires me.

from typing import List
import json


def extended_type(obj, buffer_list: List = None):
    if buffer_list is None:
        buffer_list = []
    buffer_list.append(f"<class '{type(obj).__name__}'>")
    if hasattr(obj, '__iter__') and not isinstance(obj, str):
        sub_buf = []
        for item in (obj.values() if isinstance(obj, dict) else obj):
            extended_type(item, sub_buf)
        if sub_buf:
            buffer_list.append(sub_buf)
    return buffer_list

test

def my_func():
    ...


class CC:
    ...


data_type_info: List = extended_type([(1, 'a'),
                                      [1, [2, '5', [2, 'a', CC()]]],
                                      {'a': 0, 1: 2, 'b': 's', 'l': [3, 'four']},
                                      my_func])

result: str = json.dumps(data_type_info, indent=2, sort_keys=True)
print(result)

output

[
    "<class 'list'>",
    [
        "<class 'tuple'>",
        [
            "<class 'int'>",
            "<class 'str'>"
        ],
        "<class 'list'>",
        [
            "<class 'int'>",
            "<class 'list'>",
            [
                "<class 'int'>",
                "<class 'str'>",
                "<class 'list'>",
                [
                    "<class 'int'>",
                    "<class 'str'>",
                    "<class 'CC'>"
                ]
            ]
        ],
        "<class 'dict'>",
        [
            "<class 'int'>",
            "<class 'int'>",
            "<class 'str'>",
            "<class 'list'>",
            [
                "<class 'int'>",
                "<class 'str'>"
            ]
        ],
        "<class 'function'>"
    ]
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM