2011-07-15 162 views
8

是否可以在班级定义的正文中获取班级名称?班级体内班级的Python名称

例如,

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

我知道我可以使用一个类的方法做到这一点静态外的类主体的:

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

Bar.magic() 

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

+2

这不可能在Python 2中完成,但Python 3中的元类的__prepare__方法允许您在类的主体开始执行之前将名称添加到类字典中(您可以从那里使用它) –

+0

您能描述一下您想如何使用它?这似乎有点无意义,因为你可以写Foo .__ name__而不是magic()。在某些情况下,可能会有更好的解决方案。 – viraptor

+0

@Rosh Oxymoron,我认为这是可能的,它可能不是优雅或高性能或你想要的,但只要你可以在运行时修改AST,你可以做任何你想要的... – GaretJax

回答

6

好 - 救一个解决方案 - 这一块其实没有那么复杂!

import traceback 

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

class Something(object): 
    print magic() 

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

+0

Aargh,你让我(甚至是线程安全)! :D – GaretJax

+0

@GaretJax我更喜欢动态,堆栈检查,文本解析元类:)至少它是邪恶的,没有人会尝试使用它。我看起来危险地接近“可用”。 – viraptor

+0

我可以添加这个作为我的解决方案的优势...至少有一个。 – GaretJax

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 
+0

嗯,谢谢你,这不是我想要的,因为我总是可以用__name__获得类名,但了解类装饰器可能可以解决我的问题。 – drewrobb

+3

@drewrobb:也许你可以问一个关于设计本身的问题来获得替代解决方案。 –

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

+0

这不是我的问题的答案,我想从类定义 – drewrobb

+1

@drewrobb中获取类名:并且用它做什么?任何正在执行的代码都必须从类的方法中调用,在这种情况下,您可以根据方法的类型从“cls .__ name__”或“self .__ class __.__ name__”中获取类名称。如果你想做一些非常奇怪的事情,你也可以[为它创建一个元类](http://docs.python.org/reference/datamodel.html#customizing-class-creation)。 – JAB

+0

Python 2中的元类仍然在执行主体后踢入,因此类的主体不知道类的名称。 –

1

我不知道的一种优雅的方式在Python 2.x到做到这一点 - 但它是一种解释型语言,这意味着什么大意如下比较简单会做你想要什么,如果你”将是安全的重新确定的代码被执行:

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

foo = Foo() 
print foo 
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__变量已经不抱一个字符串(我很开心这个实验)

+0

此外,它不是线程安全的;) – viraptor

+0

感谢@viraport,增加了它;;)我想知道是否有可能克服这个......也许通过锁定'NameAwareClassType'函数并在元类中解锁'__new__'方法...更加邪恶,锁定线程来创建**类**:D – GaretJax