类体中类的Python名称

时间:2011-07-15 17:27:32

标签: python metaprogramming python-2.x

是否可以在类定义的主体中获取类名?

例如,

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

我知道我可以使用类方法在类体外静态地执行此操作:

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

Bar.magic()

然而,这不是我想要的,我想要类体

中的类名

5 个答案:

答案 0 :(得分:6)

好的 - 还有一个解决方案 - 这个实际上并不复杂!

import traceback

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

class Something(object):
   print magic()

它将打印出“Something”。我不确定提取的堆栈格式是否以任何方式标准化,但它适用于python 2.6(以及2.7和3.1)

答案 1 :(得分:4)

AFAIK,在类定义被“执行”之前,类对象不可用,因此在类定义期间无法获取它。

如果您需要类名以供以后使用,但在类定义期间不使用它(例如计算其他字段名称或某些此类事物),那么您仍然可以使用类装饰器自动执行该过程。

def classname ( field ):
    def decorator ( klass ):
        setattr(klass, field, klass.__name__)
        return klass
    return decorator

(警告:未经测试。)

通过这个定义,你可以得到类似的东西:

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

你会得到包含类名的字段x,如:

print Foo.x

答案 2 :(得分:1)

我不知道在Python 2.x中执行此操作的优雅方法 - 但它是一种解释性语言,这意味着沿着以下行的相对简单的事情将做你想要的,如果你是安全的话会是安全的确定正在执行的代码:

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

foo = Foo()
print foo

答案 3 :(得分:1)

在这里,你有一个适合你特定案例的工作解决方案,但要注意(我写的主要是为了证明确实可以这样做):

  • 你不应该使用它
  • 非常具体
  • 它有很多限制
  • 我只是玩这个
  • 这是黑魔法
  • 它可能不适用于您的用例
  • 这不是线程安全
  • 我是否已经说过你不应该使用它?

无论如何,这里有代码:

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__变量不再包含字符串(我很开心尝试这个)

答案 4 :(得分:-2)

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属性获取类名。