How to determine type of nested data structures in Python?

后端 未结 2 730
攒了一身酷
攒了一身酷 2021-01-12 07:55

I am currently translating some Python to F#, specifically neural-networks-and-deep-learning .

To make sure the data structures are correctly translated the details o

相关标签:
2条回答
  • 2021-01-12 08:20

    One way to do it by hand would be:

    def type_spec_iterable(obj, name):
        tps = set(type_spec(e) for e in obj)
        if len(tps) == 1:
            return name + "<" + next(iter(tps)) + ">"
        else:
            return name + "<?>"
    
    
    def type_spec_dict(obj):
        tps = set((type_spec(k), type_spec(v)) for (k,v) in obj.iteritems())
        keytypes = set(k for (k, v) in tps)
        valtypes =  set(v for (k, v) in tps)
        kt = next(iter(keytypes)) if len(keytypes) == 1 else "?"
        vt = next(iter(valtypes)) if len(valtypes) == 1 else "?"
        return "dict<%s, %s>" % (kt, vt)
    
    
    def type_spec_tuple(obj):
        return "tuple<" + ", ".join(type_spec(e) for e in obj) + ">"
    
    
    def type_spec(obj):
        t = type(obj)
        res = {
            int: "int",
            str: "str",
            bool: "bool",
            float: "float",
            type(None): "(none)",
            list: lambda o: type_spec_iterable(o, 'list'),
            set: lambda o: type_spec_iterable(o, 'set'),
            dict: type_spec_dict,
            tuple: type_spec_tuple,
        }.get(t, lambda o: type(o).__name__)
        return res if type(res) is str else res(obj)
    
    
    if __name__ == "__main__":
        class Foo(object):
            pass
        for obj in [
            1,
            2.3,
            None,
            False,
            "hello",
            [1, 2, 3],
            ["a", "b"],
            [1, "h"],
            (False, 1, "2"),
            set([1.2, 2.3, 3.4]),
            [[1,2,3],[4,5,6],[7,8,9]],
            [(1,'a'), (2, 'b')],
            {1:'b', 2:'c'},
            [Foo()], # todo - inheritance?
        ]:
            print repr(obj), ":", type_spec(obj)
    

    This prints:

    1 : int
    2.3 : float
    None : (none)
    False : bool
    'hello' : str
    [1, 2, 3] : list<int>
    ['a', 'b'] : list<str>
    [1, 'h'] : list<?>
    (False, 1, '2') : tuple<bool, int, str>
    set([2.3, 1.2, 3.4]) : set<float>
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]] : list<list<int>>
    [(1, 'a'), (2, 'b')] : list<tuple<int, str>>
    {1: 'b', 2: 'c'} : dict<int, str>
    [<__main__.Foo object at 0x101de6c50>] : list<Foo>
    

    There's a question of how far you want to take it, and how deeply to check, with trade-offs between speed and accuracy. For example, do you want to go through all the items in a large list? Do you want to handle custom types (and tracking down common ancestors of those types)?

    Worth a read, though I'm not sure it's applicable, this PEP on type hints.

    0 讨论(0)
  • 2021-01-12 08:37

    As I commented, this is impossible in Python, because lists are untyped.

    You can still pretend to do it:

    def typ(something, depth=0):
        if depth > 63:
            return "..."
        if type(something) == tuple:
            return "<class 'tuple': <" + ", ".join(typ(ding, depth+1) for ding in something) + ">>"
        elif type(something) == list:
            return "<class 'list': " + (typ(something[0], depth+1) if something else '(empty)') + ">"
        else:
            return str(type(something))
    

    That returns the string <class 'tuple': <<class 'list': <class 'list': <class 'int'>>>,<class 'list': <class 'str'>>>> for your example.

    edit: To make it look more like F# you could do this instead:

    def typ(something, depth=0):
        if depth > 63:
            return "..."
        if type(something) == tuple:
            return " * ".join(typ(ding, depth+1) for ding in something)
        elif type(something) == list:
            return (typ(something[0]) if something else 'empty') + " []"
        else:
            return str(type(something, depth+1)).split("'")[1]
    

    which will return int [] [] * str [] in your example.

    0 讨论(0)
提交回复
热议问题