Получение имени класса экземпляра?

1438

Как узнать имя класса, который создал экземпляр объекта в Python, если функция, из которой я делаю это, является базовым классом, из которого был получен класс экземпляра?

Я думал, что модуль проверки мог бы помочь мне здесь, но, похоже, он не дает мне то, что я хочу. И если не считать анализа __class__члена, я не уверен, как получить эту информацию.

Дэн
источник
Что именно вы анализируете из переменной класса ?
sykora
1
имя верхнего уровня класса, к которому принадлежит экземпляр (без имени модуля и т. д.)
Dan
Я думаю, что наоборот будет намного сложнее (чтобы получить класс, в котором определен метод / функция).
Алексей

Ответы:

1910

Вы пробовали __name__атрибут класса? т.е. type(x).__name__даст вам название класса, который я думаю, что вы хотите.

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

Если вы все еще используете Python 2, обратите внимание, что приведенный выше метод работает только с классами нового стиля (в Python 3+ все классы являются классами "нового стиля"). Ваш код может использовать классы старого стиля. Следующее работает для обоих:

x.__class__.__name__
Сикора
источник
41
Удивительно просто. Интересно, почему dir(x.__class__)не перечислить это?
Cfi
43
Зачем использовать __class__по typeметоду? Как так: type(x).__name__. Разве призывать к двойному подчеркиванию не препятствует напрямую? Я не могу видеть, как обойти с помощью __name__, хотя.
jpmc26
25
Вы должны использовать __class__напрямую, чтобы быть совместимым с классами старого стиля, так как их тип просто instance.
Quantum7
14
Это используется достаточно часто в журналировании, коде orm и фреймворке, так что действительно должно быть встроенное имя типа (x) ... требующее, чтобы пользователь посмотрел на «смелость», чтобы получить имя , не так уж плохо, IMO.
Эрик Аронесты
5
@ErikAronesty,def typename(x): return type(x).__name__
sleblanc
392

Вы хотите имя класса в виде строки?

instance.__class__.__name__
truppo
источник
6
Или экземпляр .__ class__, чтобы получить объект класса: D
Pencilcheck
8
Безопасно ли использовать двойное подчеркивание?
Эдуард Лука
5
@EduardLuca, почему это не безопасно? Встроенные свойства используют подчеркивания, чтобы они не вызывали никакого конфликта с кодом, который вы пишете
JC Rocamonde
3
Хорошо, я знаю, что одиночные подчеркивания означают / предполагают, что метод / свойство должны быть закрытыми (хотя вы не можете реализовать частные методы в Python AFAIK), и мне было интересно, если это не так с (некоторыми) двойными подчеркиваниями тоже.
Эдуард Лука
28
@EduardLuca Двойные подчеркивания в начале только похожи на одно подчеркивание в начале, но еще более «приватные» (ищите «искажение имени питона»). Двойные подчеркивания в начале и конце различны - они зарезервированы для python и не являются частными (например, магические методы, такие как __init__ и __add__).
Легсайд Гордон
101

тип() ?

>>> class A(object):
...    def whoami(self):
...       print type(self).__name__
...
>>>
>>> class B(A):
...    pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
GHZ
источник
это то же самое, что и у ученика , но я должен разобрать этот результат вручную, что немного раздражает ...
Дан
8
Мне нравится этот. Таким образом, в базовом классе можно получить имя подкласса.
Joctee
6
или self.__class__.__name__вместо того, type(self).__name__чтобы получить такое же поведение. Если есть type()функция, которую выполняет функция, о которой я не знаю?
andreb
2
Если вы используете type(item)элемент списка, результатом будет <type 'instance'>время item.__class__.__name__удержания имени класса.
Грочни
1
Я думаю, что проблема, о которой упоминает @Grochni, имеет отношение только к определенным классам в Python 2.x, см. Здесь: stackoverflow.com/questions/6666856/…
Nate CK
43
class A:
  pass

a = A()
str(a.__class__)

Приведенный выше пример кода (при вводе в интерактивном интерпретаторе) будет генерироваться '__main__.A'в отличие от того, 'A'который генерируется при __name__вызове атрибута. Просто передавая результат A.__class__в strконструктор, анализ обрабатывается для вас. Тем не менее, вы также можете использовать следующий код, если вы хотите что-то более явное.

"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)

Такое поведение может быть предпочтительным, если у вас есть классы с одинаковыми именами, определенные в отдельных модулях.

Приведенный выше пример кода был протестирован в Python 2.7.5.

Джонатан
источник
Проверено в 2.6.6. Все еще работает хорошо.
Гамлет
29
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'
>>>
Prasath
источник
5
Это относится только к старому Python 2.x. В 3.x bclass () будет преобразован в bclass (объект). И даже тогда в Python 2.2 появились новые классы.
Алькальд
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
Ryann
источник
13

В качестве альтернативы вы можете использовать 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'
Юрий Рабешко
источник
10

Помимо захвата специального __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
10
И я бы не стал называть что-либо в моем программном обеспечении "мет".
Боборт
Связанное объяснение для __qualname__vs __name__: stackoverflow.com/questions/58108488/what-is-qualname-in-python
ti7
0

Чтобы получить имя класса экземпляра:

type(instance).__name__

или

instance.__class__.__name__

оба одинаковы

v.babak
источник