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

7

在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__'

你是不是指的是 >>> frame 而不是 >>> type - mgilson
我认为这是不可行的。正如下面的一个答案提到的那样,__module__属性可能有助于获得部分解决方案,但一般情况下是无法解决的。 - entropy
这里的实际用例是什么?你正在尝试编写什么样的代码,如果不将字符串"<type 'frame'>"转换为类型frame(并且没有访问到你获取该字符串的类型对象),则无法编写? - abarnert
应该是 type(a).__module__ - ecatmur
3个回答

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)。你不需要事先了解其他内容。

我正在寻找一种方法,在没有预先了解 types.FrameType 的情况下确定对象类型。只给出我的示例中的 a 对象,不知道 frametypes.FrameType 的情况下 - 你如何确定这一点? - grigoryvp
1
使用type(a)没有任何问题。对象就是对象,你已经找到了你想要的对象。如果需要,只需定义FrameType = type(a)即可。没有必要提前了解types.FrameType的知识。如果你查看types模块的内容,你可能会惊讶地发现他们本质上就是这样定义types.FrameType的。 - unutbu
@unu 创建堆栈跟踪仅为了检查对象类型似乎不太符合 Python 风格。 - grigoryvp
然而,如果你import types,那就是开发人员所做的。 (我同意当我第一次查看types模块内部时感到非常反感,但考虑到这是开发人员定义FrameType的方式,我认为我们没有其他选择。) - unutbu
这个问题完全是与实现相关的。在没有堆栈框架支持的 Python 实现中,inspect.currentframe() 返回 None。事实上,帧的概念并不是 Python 语言规范的一部分,而是一种实现细节。 - unutbu
显示剩余8条评论

1
unutbu的答案已经包含了所有具体的细节,但让我们退后一步。
你试图做的事情是普遍不可能的。不仅适用于帧,而且适用于任何东西。 print(x)隐式地打印出str(x)。如果你幸运的话,这与repr(x)相同,但通常它会给你一些人类可读的东西,而不是计算机可用的东西。
当然,您可以通过使用repr(x)代替str(x)来解决这个问题。但那仍然没有帮助。
一个好的经验法则是,repr(a)会给你一个无用的尖括号括起来的东西,或者一个可以eval回一个等于a的值的东西。但即使这也不能依赖;这只是一个经验法则。
在这种情况下,一旦你得到,那显然是repr的第一种类型,而且是无用的。
但是好消息是:你只需要保留x,而不是保留repr(x)并尝试以后重建x

或者,在这种情况下,保留type(a),你就有了帧类型。


实例化堆栈跟踪仅为了检查给定对象的类型对我来说似乎不太符合Pythonic :(. isinstance(something,types.FrameType)读起来更好。但它需要预先知道frame的隐藏位置。 - grigoryvp
@EyeofHell:是的,如果您事先静态地知道要检查帧,则使用types.FrameType。您可以通过阅读文档找到它的方法。只有在动态执行操作时才需要以编程方式弄清楚。 - abarnert

1

没有简单的方法来做这件事。通常,您只需使用:

x.__module__ + '.' + x.__name__

然而,如果对象无法从其模块中访问,则此方法将不起作用;例如,如果模块使用del从其命名空间中删除对象,则可能会发生这种情况。
对于类方法,PEP 3155引入了__qualname__属性;但在这种情况下也无法帮助。 type(a).__module__'__builtin__',但frame不是__builtin__模块中的名称。 这在使用C实现的类型中非常普遍。
在这种情况下,您必须知道frame类型在types模块中:
from types import FrameType as frame

这不公平 :). 我怎么可能知道 frame 实际上是来自于 types 中的 FrameType 类型呢?有没有什么方法可以在没有预先了解的情况下找出这个问题的答案? - grigoryvp
@EyeofHell:你不需要知道那个,因为你永远不需要动态地发现types.FrameType。当你知道你需要一个FrameType并且需要知道那是什么类型时,定义就在那里。另一方面,如果你已经有了一个frame a,你只需要type(a)来获取类型。重新阅读unutbu的答案;它详细解释了一切。 - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接