开发者

Python name of class in class body

开发者 https://www.devze.com 2023-03-21 02:04 出处:网络
Is it possible to get the class name within the body of a class definition? For example, class Foo(): x = magic() # x should now be \'Foo\'

Is it possible to get the class name within the body of a class definition?

For example,

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

I know 开发者_Python百科that I can do this statically outside of the class body using a class method:

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

Bar.magic()

However this isn't what I want, I want the class name in the class body


Ok - got one more solution - this one is actually not that complex!

import traceback

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

class Something(object):
   print magic()

It will print out "Something". I'm not sure if extracted stack format is standardised in any way, but it works for python 2.6 (and 2.7 and 3.1)


AFAIK, the class object is not available until the class definition has been "executed", so it's not possible to get it during class definition.

If you need the class name for later use but don't use it during class definition (e.g. to compute other field names, or some such thing), then you can still automate the process using a class decorator.

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

(Caveat: not tested.)

With this definition, you can get something like:

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

and you would get field x with the class name in it, as in:

print Foo.x


Here you have a working solution for your specific case, but beware (I wrote it mainly to demonstrate that it IS indeed possible to do something like this):

  • You shouldn't use it
  • It is very specific
  • It has many limitations
  • I was just having fun with this
  • It is black magic
  • It may not work for your use case
  • It is not threadsafe
  • Do I have already said that you shouldn't use it?

Anyway, here you have the code:

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__

Edit: https://gist.github.com/1085475 — there you have a version which allows to use __clsname__ during method execution; makes not much sense, as self.__class__.__name__ is a better approach and the __clsname__ variable does not hold a string anymore (I'm having fun experimenting with this)


I don't know of an elegant way to do this in Python 2.x -- but it's an interpreted language which means that something relatively simple along the following lines will do what you want and would be safe if you're sure of the code being executed:

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

foo = Foo()
print foo


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'

This way you can use x as an attribute, at least within any instance and static methods. In class methods, you can just get the class name from the cls attribute anyway.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号