Search code examples
pythonclassclassname

Storing the class name in class variable without typing the name of the class?


In an instance method of a python class, I know that we can get the class name via self.__class__.__name__

However, I'd like to store the name of a class in a class variable, without coding the name of the class.

I know I can do this to get a class's name into a class variable:

class MyClass(object):
  pass
MyClass._myname = MyClass.__name__

However, I have to code the string MyClass two times outside of the class definition, simply to get the class name into a class variable. In this case, that would be "MyClass", which I could simply code as follows:

class MyClass(object):
  _myname = "MyClass"

But even that is redundant, given that I have to hard-code "MyClass" within the MyClass class.

What I'd like is to somehow get a class's name into a class variable without coding the class's name, as follows:

class MyClass(object):
  _myname = ???? # where ???? is a statement which returns the class
                 # name, in which the string "MyClass" does not appear

Is this even possible?


Solution

  • You could use a decorator

    >>> def autoname(cls):
    ...    cls._MyName=cls.__name__
    ...    return cls
    ... 
    >>> @autoname
    ... class check:
    ...    pass
    ... 
    >>> check._MyName
    'check'
    >>> 
    

    Or if you do not want to hard-code the name of the attribute:

    >>> def autoname2(name):
    ...     def autoname(cls):
    ...         setattr(cls, name, cls.__name__)
    ...         return cls
    ...     return autoname
    ...
    >>> @autoname2('_StoreHere')
    ... class check2:
    ...     pass
    ... 
    >>> check2._StoreHere
    'check2'
    >>> 
    

    Of course, the second form can take more parameters, for example:

    >>> def autoname3(name, f=lambda x: x):
    ...     def autoname(cls):
    ...         setattr(cls, name, f(cls.__name__))
    ...         return cls
    ...     return autoname
    ...
    >>> @autoname3('_MyNameIs', lambda x: x.upper() + '_The_Bold')
    ... class check3:
    ...     pass
    ... 
    >>> check3._MyNameIs
    'CHECK3_The_Bold'
    >>>
    

    A note on decorator vs metaclass: Metaclasses are seriously cool, nonetheless, if one doesn't strictly need them they are better avoided because of the infamous metaclass conflicts.