如何在Python中获取完整类型名?

8 投票
3 回答
11651 浏览
提问于 2025-04-17 17:37

在Python中,使用type()函数打印结果时,有时候会显示一些在当前环境中并不存在的类型名称。例如,下面的代码会显示"<type 'frame'>"

import inspect
a = inspect.currentframe()
print( type( a ) )

但是在当前环境中并没有frame这个类型!如果我在交互式解释器中尝试使用它,就会出现错误:

>>> frame
NameError: name 'frame' is not defined

那么有没有办法获取一个“完整的”类型名称,比如“inspect.something.frame”,这样我就可以在我的代码中引用它呢?

更新

不幸的是,__module__也不起作用:

>>> type( a ).__module__
'__builtin__'

3 个回答

1

unutbu的回答已经包含了所有具体的细节,但我们可以稍微退后一步来看。

你想做的事情,从整体上来说,是不可能的。这不仅仅是针对框架来说,对于任何东西都是如此。

print(x) 实际上是隐式地打印出 str(x) 的结果。如果你运气好,这个结果和 repr(x) 是一样的,但通常它给你的是人类可读的内容,而不是计算机能直接使用的。

当然,你可以通过使用 repr(x) 来绕过这个问题,而不是 str(x)。但这 仍然 不能解决问题。

一个简单的经验法则是,repr(a) 要么给你一些包裹在尖括号里的无用信息,要么给你一些可以用 eval 重新计算回原值的内容,使得 == a 成立。但即便如此,这也不能完全依赖;这只是一个经验法则。

在这种情况下,一旦你得到了 <type 'frame'>,这显然是第一种 repr 的情况,而它是无用的。

但好消息是:你只需要保留 x,而不是保留 repr(x) 然后试图在后面重建 x

或者,在这个例子中,保留 type(a),这样你就得到了框架的类型。

1

这件事没有简单的方法来解决。一般来说,你可以直接使用:

x.__module__ + '.' + x.__name__

不过,如果这个对象在它的模块中不可访问,这种方法就不管用了;比如说,如果模块使用了del来把这个对象从它的命名空间中删除,就会出现这种情况。

对于类的方法,PEP 3155引入了__qualname__这个属性;但在这种情况下也没有帮助。type(a).__module__的值是'__builtin__',但是frame并不是__builtin__模块中的一个名称。这种情况在用C语言实现的类型中比较常见。

在这种情况下,你需要知道frame类型是在types模块中的:

from types import FrameType as frame
3

"What's in a name? That which we call a frame 
 By any other name would smell as sweet."

如果你想找到一个框架对应的Python对象类型,可以使用:

In [38]: import types

In [39]: types.FrameType
Out[39]: <type 'frame'>

当然,这其实就是另一种写法,跟 type(a) 是一样的:

In [42]: import inspect

In [43]: a = inspect.currentframe()

In [44]: types.FrameType == type(a)
Out[44]: True

如果你查看一下 types 模块,你会发现 types.FrameType 是这样定义的:

try:
    raise TypeError
except TypeError:
    tb = sys.exc_info()[2]
    TracebackType = type(tb)
    FrameType = type(tb.tb_frame)
    del tb

他们所做的就是找到一个 frame 的实例,然后把 FrameType 定义为这个实例的 type

这其实就是你在定义的时候所做的事情。

MyFrameType = type(a)

所以结论就是:要获取一个实例的类型,只需调用 type(obj)。你不需要事先知道其他任何东西。

撰写回答