Skip to content

Different types of inner classes in Python 2 and Python 3

I am upgrading my project from Python 2.7 to Python 3.7 and in my code I have something like this:

class A:
  class B(Exception):

now type(A.B()) returns different things in the two Python versions:

In Python 2.7 I get: <class '__main__.B'>

In Python 3.7 I get: <class '__main__.A.B'>

Can anybody explain what happens under the hood that causes this difference?

Thank you very much!


This is a result of the changes made for PEP 3155: Qualified name for classes and functions. When a class or function is defined inside another class, its __qualname__ attribute includes the information on the class it was defined inside (non-nested cases also get it, but it’s the same as __name__ there). Nothing changed about the behavior of the classes, just the display information; the repr of classes uses __qualname__ to make the source of the class more obvious to users.

Part of the motivation for it was that it was handy to know when a function was defined inside a class, but Python 3 removed the concept of unbound methods (they’re just plain functions that implement the descriptor protocol to become bound methods when accessed through an instance of the class), so this restored some of the introspection capabilities without reintroducing unbound methods (which were removed for being largely unnecessary, and slowing code).