Search code examples
pythonpython-3.xclass-variables

Python Class Name as Class Variable


I'm working as an application with classes and subclasses. For each class, both super and sub, there is a class variable called label. I would like the label variable for the super class to default to the class name. For example:

class Super():
    label = 'Super'

class Sub(Super):
    label = 'Sub'

Rather than manually type out the variable for each class, is it possible to derive the variable from the class name in the super class and have it automatically populated for the subclasses?

class Super():
    label = # Code to get class name

class Sub(Super)
    pass
    # When inherited Sub.label == 'Sub'.

The reason for this is that this will be the default behavior. I'm also hoping that if I can get the default behavior, I can override it later by specifying an alternate label.

class SecondSub(Super):
    label = 'Pie'  # Override the default of SecondSub.label == 'SecondSub'

I've tried using __name__, but that's not working and just gives me '__main__'.

I would like to use the class variable label in @classmethod methods. So I would like to be able to reference the value without having to actually create a Super() or Sub() object, like below:

class Super():
    label = # Magic

    @classmethod
    def do_something_with_label(cls):
        print(cls.label)

Solution

  • A metaclass might be useful here.

    class Labeller(type):
        def __new__(meta, name, bases, dct):
            dct.setdefault('label', name)
            return super(Labeller, meta).__new__(meta, name, bases, dct)
    
    # Python 2
    # class Super(object):
    #    __metaclass__ = Labeller
    
    class Super(metaclass=Labeller):
        pass
    
    class Sub(Super):
        pass
    
    class SecondSub(Super):
        label = 'Pie'
    
    class ThirdSub(SecondSub):
        pass
    

    Disclaimer: when providing a custom metaclass for your class, you need to make sure it is compatible with whatever metaclass(es) are used by any class in its ancestry. Generally, this means making sure your metaclass inherits from all the other metaclasses, but it can be nontrivial to do so. In practice, metaclasses aren't so commonly used, so it's usually just a matter of subclassing type, but it's something to be aware of.