Python имя класса в теле класса - PullRequest
9 голосов
/ 15 июля 2011

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

Например,

class Foo():
    x = magic() # x should now be 'Foo'

Я знаю, что могу делать это статически вне тела класса.используя метод класса:

class Bar():
    @classmethod
    def magic(cls):
        print cls.__name__

Bar.magic()

Однако это не то, что я хочу, я хочу имя класса в теле класса

Ответы [ 5 ]

6 голосов
/ 16 июля 2011

Хорошо - есть еще одно решение - это на самом деле не так уж и сложно!

import traceback

def magic():
   return traceback.extract_stack()[-2][2]

class Something(object):
   print magic()

Он выведет «Something».Я не уверен, что формат извлеченного стека каким-либо образом стандартизирован, но он работает для Python 2.6 (и 2.7 и 3.1)

4 голосов
/ 15 июля 2011

AFAIK, объект класса недоступен до тех пор, пока определение класса не будет «выполнено», поэтому его невозможно получить во время определения класса.

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

С этим определением вы можете получить что-то вроде:

@classname(field='x')
class Foo:
    pass

, и вы получите поле x с именем класса в нем, как в:

print Foo.x
1 голос
/ 15 июля 2011

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

  • Вы не должны его использовать
  • Это очень специфично
  • У него много ограничений
  • Мне было просто весело с этим
  • Это черная магия
  • Этоможет не работать в вашем случае использования
  • Это не потокобезопасно
  • Я уже говорил, что вы не должны его использовать?

В любом случае, здесь у вас естькод:

import inspect

def NameAwareClassType():
    frameInfo = inspect.getouterframes(inspect.currentframe())[1]
    codeContext = frameInfo[4][0]
    className = codeContext.split(' ', 1)[1].split('(', 1)[0]

    class ClassNameGlobalRemoverType(type):
        def __new__(mcs, name, bases, dict):
            if name == className:
                del globals()['__clsname__']
            return type.__new__(mcs, name, bases, dict)

    class NameAwareClass(object):
        __metaclass__ = ClassNameGlobalRemoverType

    globals()['__clsname__'] = className

    return NameAwareClass

class A(NameAwareClassType()):

    print __clsname__

    def __init__(self):
        pass

print __clsname__

Редактировать: https://gist.github.com/1085475 - там у вас есть версия, которая позволяет использовать __clsname__ во время выполнения метода;не имеет особого смысла, так как self.__class__.__name__ - лучший подход, а переменная __clsname__ больше не содержит строку (мне весело экспериментировать с этим)

1 голос
/ 15 июля 2011

Я не знаю элегантного способа сделать это в Python 2.x - но это интерпретированный язык, который означает, что что-то относительно простое в следующих строках будет делать то, что вы хотите, и будет безопасно, если выуверен в выполнении кода:

classdef = """\
class %(classname)s(object):
    x = '%(classname)s'
    print x
"""
exec classdef % {'classname': 'Foo'}

foo = Foo()
print foo
0 голосов
/ 15 июля 2011
class Bar():

    @classmethod
    def magic(cls):
        return cls.__name__

    @property
    def x(self):
        return self.magic()

    def y(self):
        return self.x

>>> a = Bar()
>>> a.x
'Bar'
>>> a.y()
'Bar'

Таким образом, вы можете использовать x в качестве атрибута, по крайней мере, в любом экземпляре и статических методах.В методах класса вы можете в любом случае просто получить имя класса из атрибута cls.

...