Python получает имя класса - программирование
Подтвердить что ты не робот

Python получает имя класса

Итак, у меня есть эта проблема, я хочу получить имя класса python таким образом:

class TestClass():
    myName = (get class name here automatically)
    saveDirectory = os.path.join(saveDir, myName) # so i can save it in unique location
    def __init__(self):
        pass # do something

Однако, похоже, что __class__.__name__ на самом деле не существует в момент создания myName. Поэтому я был вынужден включить это в функцию __init__(), например:

class TestClass():
    def __init__(self):
        self.myName = self.__class__.__name__
        saveDirectory = os.path.join(saveDir, self.myName) # so i can save it in unique location
        pass # do something

Но это имеет большую проблему, потому что я не могу получить имя класса до тех пор, пока не создам экземпляр класса. Я хочу создать несколько гигабайт данных для каждого экземпляра класса, который будет сохранен в saveDirectory, поэтому он может повторно использовать позже. Поэтому я действительно не хочу делать свое текущее решение.

В любом случае, чтобы получить имя класса, как я предполагал? Или я просто мечтаю?

EDIT:

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

4b9b3361

Ответ 1

Единственный способ сделать то, что вы пытаетесь во время определения класса, - использовать метакласс:

def saveDirMeta(name, bases, dct):
    dct['saveDirectory'] = os.path.join(saveDir, name)
    return type(name, bases, dct)

class TestClass(object):
    __metaclass__ = saveDirMeta  # this adds the 'saveDirectory' attribute
    def __init__(self):
        pass # do something

Или на Python 3.x:

class TestClass(metaclass=saveDirMeta):
    def __init__(self):
        pass # do something

Это определенно менее понятно, чем просто использовать следующее:

class TestClass():
    saveDirectory = os.path.join(saveDir, 'TestClass')
    def __init__(self):
        pass # do something

Ответ 2

Просто используйте метод?

class TestClass(object):
    @classmethod
    def get_save_directory(cls):
        return os.path.join(save_dir, cls.__name__)

Или вы можете просто иметь атрибут класса, указывающий каталог сохранения; меньше магии, как правило, хорошо. Кроме того, вы можете изменить имя класса позже, не нарушая ваше хранилище.

И что? Гигабайт?!

Ответ 3

Я предполагаю, что то, что вы делаете, невозможно, потому что класс даже не существует, когда вы делаете:

myName = (get class name here automatically)

Но вскоре после интерпретации класса вы можете передать объект класса другой функции чтобы выполнить эту работу за вас.

In [1]: def save_class(cl):
    myName = cl.__name__
    print myName        #or do whatever you wanna do here
   ...:     

In [2]: class A:pass

In [3]: save_class(A)
A

Ответ 4

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

Не имея хорошего ответа на этот выдающийся вопрос, остается попытаться получить имя класса из:

1. outside the interpreted class definition, uninstantiated

    class demo(object):
        pass

    print demo.__name__ # 'demo'


2. from within the class definition, uninstantiated (or instantiated ;-)

    class demo2(object):
        @classmethod
        def myName(cls):
            return cls.__name__

    print demo2.myName() # 'demo2'
    print demo2().myName() # 'demo2'


or

3. within an actual instance of the class

    class demo3(object):
        def myClassName(self):
            return self.__class__.__name__

    print demo3().myClassName() # 'demo3'

Кроме того, пожалуйста, отредактируйте вопрос и добавьте некоторые детали, объясняющие, почему ваша первоначальная попытка должна работать так, как вы хотите, до создания экземпляра и, тем не менее, внутреннего определения класса, в то время как ваш второй пример проблематичен. Кроме того, как saveDir получает или приходит? (Глобальный за пределами класса?) Пожалуйста, покажите код, показывающий, как вы собираетесь использовать то, что хотите работать. Там может быть способ редизайна, чтобы добраться туда отсюда, по сути, если не буквально.

Ответ 5

Помимо метакласса в F J answer, я могу думать о двух других способах. Я начну с более красивого вида. Вам не нужно использовать метакласс; иногда дескриптор вполне адекватен.

class ClassNameDescriptor(object):
    def __get__(self, instance, owner):
        return owner.__name__

class BaseClass(object):
    name = ClassNameDescriptor()

class Foo(BaseClass):
    pass

В противном случае, если вам действительно нужно имя класса внутри тела класса (маловероятно), вы можете snoop в стеке вызовов. Имя класса, как он появляется в источнике, находится на объекте кода, выполняемом определением класса:

import sys

def get_class_name_from_inside_class():
    return sys._getframe().f_back.f_code.co_name

class Foo(object):
    name = get_class_name_from_inside_class()
    print name

Из представленных ранее, только этот последний позволяет вам использовать имя как строку изнутри тела класса, к сожалению, это не работает во всех версиях python, особенно IronPython не реализует как он не доступен в DLR.

Есть способ получить его, не задумываясь над стеком, с возможностью переносимости. Это похоже на ответ, предоставленный F J, с использованием метакласса, но вместо этого использует функцию __prepare__, доступную в Python 3:

class namedMeta(type):
    def __prepare__(mcls, name, bases, **kwargs):
        return {'name': name}

class Foo(metaclass=named):
    print name

Ответ 6

попробуйте это. вы можете ссылаться на свой текущий класс на _class. (Я использую python 2.7)

class Meta(type):
    def __init__(self, *args):
        super(Meta, self).__init__(*args)
        self._class = self
        self.saveDir = str(self._class)

class Wow(object):
     __metaclass__ = Meta

>>> Wow.saveDir
>>> Wow().saveDir

Ответ 7

С python 3.3 вы можете использовать переменную __qualname__:

class TestClass():
    myName = __qualname__