如何找到复杂对象的类型

时间:2018-01-30 04:55:20

标签: python tensorflow types

给定任何python对象,有没有办法打印出它的结构,这样你就可以理解如何用等效结构的对象替换它?

上下文:我一直在尝试自定义this Tensorflow example code,因此它适用于我自己的数据。在将batch[0]batch[1]传递给accuracy.eval()函数时,我似乎在第163行摔倒了。我认为batch将是两种不同数据类型的元组,但我真的不确定这两个项的数据类型是什么,也不确定它们与基本python类型的关系(例如我认为它们都应该是numpy ndarray不同大小的类型,但这是否相当于列表列表......?)

我想我可以撒上几个print(type(batch[0]))语句来找到答案...我的数据类型很深,所以编辑的数量很多。是否有代码会在一次点击中显示此结构,无论涉及哪种数据类型?

1 个答案:

答案 0 :(得分:2)

据我所知,没有内置的方法来了解Python中某些对象的内部结构,但如果我错了,有人会纠正我。我假设你只关心类型嵌套结构,而不是数组长度或任何东西,尽管很容易将它们添加到输出中。

递归解决方案

您可能希望编写一个递归函数,该函数在给定的递归深度后终止。我刚才在某个地方拾起了类似的东西并稍微改了一下。 这变得非常快,但原则上工作正常。但是,您必须添加要自己递归的对象层。

import numpy as np
def type_recurse(obj, depth=0):
    if depth > 20:
        return "..."
    if isinstance(obj, tuple):
        return "<class 'tuple': <" + ", ".join(type_recurse(inner, depth+1) for inner in obj) + ">>"
    elif isinstance(obj,list):
        return "<class 'list': " + (type_recurse(obj[0], depth+1) if obj else '(empty)') + ">"
    elif isinstance(obj,dict):
        return "<class 'dict': " + ", ".join(type_recurse(key, depth+1)+":"+type_recurse(val,depth+1) for key,val in obj.items()) + ">"
    elif isinstance(obj,np.ndarray):
        return "<class 'np.ndarray': " +", ".join(type_recurse(inner, depth+1) for inner in obj) + ">"
    else:
        return str(type(obj))

if __name__ == "__main__":
    a= (1,1)
    b= (1,1)
    c= (a,b)
    f = {"oh":c}
    g = np.array([1,"ah",f])
    print(type_recurse(g))

另请注意,列表和数组确实被识别为不同的类型。

迭代解决方案

提出另一种方法:只要当前对象中存在任何可迭代结构,就迭代您的对象,收集类型。我做了一些看起来与上面类似的格式,但你可以根据需要改变它。此外,如果你需要长度等(因为你说用完全相同的对象结构替换),任何一个迭代层打开时附加它们都不应该是一个问题。 len()方法适用于数组,元组和列表,因此+str(len(value))语句中的简单try应该有效。

def iter_type(iterable):
    """ prints the internal type structure of any iterable object """
    iterator, sentinel, stack = iter(iterable), object(), []
    fulltype = str(type(iterable))[0:-1]+": " # open highest layer
    while True:
        value = next(iterator, sentinel)
        if value is sentinel:
            if not stack:
                fulltype = fulltype[0:-3]+">" # neglect last comma and close highest layer
                break
            fulltype = fulltype[0:-3]+"> , " # iterator closes
            iterator = stack.pop()
        else:
            try:
                new_iterator = iter(value)
                fulltype += str(type(value))[0:-1]+ ": " # open iterable type layer, neglect last comma
            except TypeError: # non-iterable values
                fulltype += str(type(value))+" , " 
            else:
                stack.append(iterator)
                iterator = new_iterator
    return fulltype 

我无法保证完全的通用性,您需要对其进行测试。但是下面的例子:

if __name__ == "__main__":
    print(iter_type([1,2,np.array([2,3]), [1,2],2]))

打印:

<class 'list': <class 'int'> , <class 'int'> , <class 'numpy.ndarray': <class 'numpy.int64'> , <class 'numpy.int64'>> , <class 'list': <class 'int'> , <class 'int'>> , <class 'int'>>

正如所料。涉及元组对我来说也很好。

进一步说明如果您的iterables预计包含许多元素,那么打印对象类型及其编号而不是可迭代对象的所有元素类型可能更为明智,可能更改是不是很难实现,但我没有尝试,因为我从来没有需要它。