Получить имя текущего класса?

102

Как мне узнать название класса, в котором я сейчас учусь?

Пример:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

Из-за характера программы, с которой я взаимодействую (vistrails), я не могу использовать ее __init__()для инициализации input.

Джонатан Гинзбург
источник

Ответы:

158

obj.__class__.__name__ даст вам любое имя объекта, поэтому вы можете сделать это:

class Clazz():
    def getName(self):
        return self.__class__.__name__

Использование:

>>> c = Clazz()
>>> c.getName()
'Clazz'
Юваль Адам
источник
1
Почему это не принятый ответ? РЕДАКТИРОВАТЬ: Хорошо, область действия OP не внутренняя, она на уровне класса.
KomodoDave
6
@KomodoDave, потому что это неправильно даже в области действия метода. Когда вы вызываете getNameдочерний класс, он выводит имя дочернего класса. Затем становится сложно, если вам ДЕЙСТВИТЕЛЬНО нужен класс, с которым вы работаете.
Кенет Джервет
@KenetJervet Вы имеете в виду , когда вы звоните getNameиз родительского класса он будет выводить имя класса ребенка? Хорошо, что указали на это.
KomodoDave
5
С точки зрения объектно-ориентированного подхода решение (возвращающее фактическое имя дочернего класса среды выполнения, даже если getName()метод определен в суперклассе) является правильным.
sxc731
22

В теле класса имя класса еще не определено, поэтому оно недоступно. Вы не можете просто ввести имя класса? Возможно, вам нужно подробнее рассказать о проблеме, чтобы мы смогли найти для вас решение.

Я бы создал метакласс, чтобы делать эту работу за вас. Он вызывается во время создания класса (концептуально в самом конце class: block) и может управлять создаваемым классом. Я не тестировал это:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'
Нед Батчелдер
источник
ЧТОБЫ прояснить, что я пытаюсь сделать: мне нужно создать и инициализировать переменную класса 'input' вне метода . У меня есть несколько небольших классов, каждый из которых должен вызывать get_input, используя имя своего класса в качестве параметра. Я пытаюсь обобщить это, чтобы мне не приходилось переходить к каждому классу (их будет около 100) и вводить имя класса.
Джонатан Гинзбург
Хорошо, я обновил свой ответ метаклассом, который должен помочь.
Нед Батчелдер
1
Что означает MyTypeв superстроке InputAssigningMetaclass?
A.Wan 01
16

Вы можете получить к нему доступ через приватные атрибуты класса:

cls_name = self.__class__.__name__

РЕДАКТИРОВАТЬ:

Как сказано Ned Batcheler, это не будет работать в теле класса, но будет работать в методе.

mdeous
источник
11

Представлен PEP 3155__qualname__ , реализованный в Python 3.3.

Для функций и классов верхнего уровня __qualname__атрибут равен __name__атрибуту. Для вложенных классов, методов и вложенных функций __qualname__атрибут содержит пунктирный путь, ведущий к объекту из модуля верхнего уровня.

Он доступен из самого определения класса или функции, например:

class Foo:
    print(__qualname__)

будет эффективно печатать Foo. Вы получите полное имя (за исключением имени модуля), поэтому вы можете разделить его на .символ.

Однако нет никакого способа получить реальный дескриптор определяемого класса.

>>> class Foo:
...     print('Foo' in globals())
... 
False
Правая нога
источник
7

РЕДАКТИРОВАТЬ: Да, вы можете; но вы должны обмануть: имя текущего запущенного класса присутствует в стеке вызовов, и tracebackмодуль позволяет вам получить доступ к стеку.

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

Однако я бы не стал этого делать; Мой первоначальный ответ по-прежнему является моим предпочтением в качестве решения. Оригинальный ответ:

возможно, самым простым решением является использование декоратора, который похож на ответ Неда с участием метаклассов, но менее мощный (декораторы способны к черной магии, но метаклассы способны к древней оккультной черной магии)

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 
SingleNegationElimination
источник
1
import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()
Павел Патрин
источник
1

Думаю, должно быть так:

    class foo():
        input = get_input(__qualname__)
Штефан
источник