youngmit
youngmit

Reputation: 868

How is the default __repr__ implemented for python type objects?

Say I create a new class as part of a metaclass:

import six

class Meta(type):
    def __new__(mcl, name, bases, attrs):
        nt = type.__new__(mcl, name, bases, attrs)

        class NestedClass(object):
            pass
        print(NestedClass)

        return nt

class Foo(six.with_metaclass(Meta), object):
    pass

In Python 2, I get: <class '__main__.NestedClass'> whereas in Python 3, I get: <class '__main__.Meta.__new__.<locals>.NestedClass'>

I know that I can control the behavior of __repr__() by implementing my own version on Meta, for example:

class Meta(type):
    # ...
    def __repr__(self):
        return "<class '{}'>.format(self.__name__)"

However, I am mostly curious where the default Python 3 version is getting "__main__.Meta.__new__.<locals>." from at call time. Inspecting the class object, I am not seeing any state that stores it. Is it getting baked straight into the __repr__() function itself?

Upvotes: 0

Views: 484

Answers (1)

anthony sottile
anthony sottile

Reputation: 70223

This comes from the combination of __module__ and __qualname__ (new in python3 via PEP 3155)

Adjusting your example slightly:

import six

class Meta(type):
    def __new__(mcl, name, bases, attrs):
        nt = type.__new__(mcl, name, bases, attrs)

        class NestedClass(object):
            pass
        print(NestedClass)
        # vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        print(NestedClass.__module__)
        print(NestedClass.__qualname__)
        # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        return nt

class Foo(six.with_metaclass(Meta), object):
    pass

Produces the following output:

$ python3 t.py 
<class '__main__.Meta.__new__.<locals>.NestedClass'>
__main__
Meta.__new__.<locals>.NestedClass

Note that python 2.x does not have __qualname__ so you'll need to adjust with something like getattr(cls, '__qualname__', '__name__') to be compatible

Upvotes: 2

Related Questions