Search code examples
pythonpython-3.xoopmetaclassrepr

Class __repr__ of a metaclass, not a class


I am aware of the ability to define a 'class repr' by using a metaclass. However, I need the functionality of returning the metaclass with its own __repr__ as such:

class Meta(type):
    def __repr__(cls):
        return 'Person class: {}'.format(cls.__name__)


class Person(metaclass=Meta):
    def __init__(self, name, age, job):
        self.name = name
        self.job = job
        self.age = age

    def __str__(self):
        return 'Person: {}, {}, {}'.format(self.name,
                                           self.age,
                                           self.job)


class Employee(Person):
    def __init__(self, name, age):
        super(Employee, self).__init__(name, age, 'employee')


class Manager(Person):
    def __init__(self, name, age):
        super(Manager, self).__init__(name, age, 'manager')

m = Manager('bob', 79)
e = Employee('stephen', 25)

As expected, type(e) and type(m) return their respective 'Person class: ...', however, if I do type(Employee), I get <class '__main__.Meta'>. I need this class to have its own __repr__ as the actual implementation I am using consists of a base Type class with subclasses of String, Number, etc. Calling type on the instances works just fine, but since type may be also called on the class, I need a more 'user-friendly' return string.


Solution

  • Actually, nothing would prevent you from writting a meta-meta class with the __repr__ for the metaclass itself:

    In [2]: class MM(type):
       ...:     def __repr__(cls):
       ...:         return f"<metaclass {cls.__name__}"
       ...:      
    
    In [3]: class M(type, metaclass=MM):
       ...:     def __repr__(cls):
       ...:         return f"<class {cls.__name__}>"
       ...:     
    
    In [4]: class O(metaclass=M):
       ...:     pass
       ...: 
    
    In [5]: o = O()
    
    In [6]: o
    Out[6]: <<class O> at 0x7ff7e0089128>
    
    In [7]: O
    Out[7]: <class O>
    

    The output of repr(M):

    In [8]: repr(M)
    Out[8]: '<metaclass M'
    

    (The confusing thing here is that type is also the metaclass for type itself - that is reflected here in that M does not inherit from MM, but rather, have it as its metaclass).