获取实例的类名

1933

我该如何在Python中查找用于创建对象实例的类名?

我不确定是否应该使用inspect模块还是解析__class__属性。


你从 class 变量中“解析”出了什么? - sykora
2
实例所属类的顶层名称(不包括模块名称等...)。 - Dan
12个回答

2512

你尝试过使用类的__name__属性了吗?例如,type(x).__name__将会返回类名,这也是你所需要的。

>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'

如果您仍在使用Python 2,请注意上述方法仅适用于新式类(在Python 3+中,所有类都是“新式”类)。您的代码可能会使用一些旧式类。以下方法适用于两种类型:

x.__class__.__name__

49
惊人的简单。不知道为什么dir(x.__class__)没有列出它? - cfi
52
为什么要使用 __class__ 而不是 type 方法呢?比如:type(x).__name__。直接调用双下划线成员不被鼓励,但我看不出有其他方法可以使用 __name__ - jpmc26
26
如果要与旧式类兼容,则必须直接使用__class__,因为旧式类的类型只是instance - Quantum7
25
在日志、ORM和框架代码中,经常使用typename(x),以致于实际上应该有一个内置的typename函数。让用户查看“内部结构”以获取__name__并不是Pythonic的做法,我个人认为。 - Erik Aronesty
8
def typename(x): return type(x).name - sleblanc
显示剩余5条评论

536
你希望将类的名称作为字符串返回吗?
instance.__class__.__name__

9
可以使用实例.__class__来获取类对象 :D - Pencilcheck
9
使用双下划线属性安全吗? - Eduard Luca
7
@EduardLuca 为什么不安全?内置属性使用下划线以避免其与您编写的代码发生冲突。 - user4396006
3
我知道单下划线表示方法/属性应该是私有的(虽然我认为在Python中你无法真正实现私有方法),我想知道是否双下划线也是这种情况(至少在某些情况下是这样)。 - Eduard Luca
46
双下划线开头的命名方式和单下划线开头类似,但更加“私有”(可查阅“Python名称重整”)。双下划线同时出现在开头和结尾的命名方式则不同——这些被保留给 Python 使用,不是私有的(例如魔术方法如 init 和 __add__)。 - Leagsaidh Gordon
显示剩余3条评论

177

type() 是什么?

>>> class A:
...     def whoami(self):
...         print(type(self).__name__)
...
>>>
>>> class B(A):
...     pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>

12
我喜欢这个。这样,在基类中就可以获取子类的名称。 - joctee
15
可以使用 self.__class__.__name__ 替代 type(self).__name__ 来实现相同的功能。除非有一些我不知道的关于 type() 函数的特性? - andreb
3
如果您在列表项上使用 type(item),结果将是 <type 'instance'>,而 item.__class__.__name__ 则包含类名。 - Grochni
1
我认为@Grochni提到的问题只适用于Python 2.x中的某些类,请参见此处:https://dev59.com/OGw15IYBdhLWcg3wWqf- - Nate C-K
@andreb 原始解决方案更短。 - OrrinPants

51
class A:
  pass

a = A()
str(a.__class__)
上面的示例代码(在交互式解释器中输入)将生成'__main__.A',而如果调用__name__属性,则会生成'A'。通过将A.__class__的结果简单地传递给str构造函数,您可以处理解析。但是,如果需要更明确的内容,也可以使用以下代码。
"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)

如果您在不同的模块中定义了相同名称的类,那么这种行为可能更可取。

以上提供的示例代码已在Python 2.7.5中进行了测试。


30

在Python 2中,

type(instance).__name__ != instance.__class__.__name__
# if class A is defined like
class A():
   ...

type(instance) == instance.__class__
# if class A is defined like
class A(object):
  ...

例子:

>>> class aclass(object):
...   pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>


>>> class bclass():
...   pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>

6
这仅适用于旧版 Python 2.x。在3.x中,bclass()将解析为bclass(object)。即便如此,在Python 2.2中也出现了新的类。 - alcalde

24

或者你可以使用 classmethod 装饰器:

class A:
    @classmethod
    def get_classname(cls):
        return cls.__name__

    def use_classname(self):
        return self.get_classname()

用法:

>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'

16

问题很好。

这是一个简单的例子,基于GHZ的想法,可能会帮助一些人:

>>> class person(object):
        def init(self,name):
            self.name=name
        def info(self)
            print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person

16

除了获取特殊的 __name__ 属性之外,您可能需要获取给定类/函数的限定名称。这可以通过获取类型的 __qualname__ 来完成。

在大多数情况下,它们将完全相同,但是当处理嵌套类/方法时,您会得到不同的输出。例如:

class Spam:
    def meth(self):
        pass
    class Bar:
        pass

>>> s = Spam()
>>> type(s).__name__ 
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__       # type not needed here
'Bar'
>>> type(s).Bar.__qualname__   # type not needed here 
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'

既然你需要内省,这可能是你想考虑的方法。


2
需要注意的是,__qualname__ 是适用于 Python 3.3 及以上版本的。 - FireAphis
15
我会尽力将以下内容翻译成通俗易懂的中文,不过不会改变原意:我会避免在我的软件中使用“meth”这个名称。 - Bobort
__qualname____name__的相关解释:https://dev59.com/llMH5IYBdhLWcg3w0jeF - ti7

11
你可以简单地使用__qualname__,它代表一个函数或类的限定名称
示例:
>>> class C:
...     class D:
...         def meth(self):
...             pass
...
>>> C.__qualname__
'C'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__qualname__
'C.D.meth'

文档链接 qualname


2
这个翻译是:“这给出了一个类的名称,而不是实例的类名。” - pascal sautot
这个建议已经在2017年被@Dimitris提出过了。 - Rimov

7

获取实例的类名:

type(instance).__name__

或者

instance.__class__.__name__

两者是相同的。


实际上它们可以不同,如果类重写了__class__,或者在旧式类(已经过时)中。 - wjandrea

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