PEP: 3155 Title: Qualified name for classes and functions Version:
$Revision$ Last-Modified: $Date$ Author: Antoine Pitrou
<solipsis@pitrou.net> Status: Final Type: Standards Track Content-Type:
text/x-rst Created: 29-Oct-2011 Python-Version: 3.3 Post-History:
Resolution:
https://mail.python.org/pipermail/python-dev/2011-November/114545.html

Rationale

Python's introspection facilities have long had poor support for nested
classes. Given a class object, it is impossible to know whether it was
defined inside another class or at module top-level; and, if the former,
it is also impossible to know in which class it was defined. While use
of nested classes is often considered poor style, the only reason for
them to have second class introspection support is a lousy pun.

Python 3 adds insult to injury by dropping what was formerly known as
unbound methods. In Python 2, given the following definition:

    class C:
        def f():
            pass

you can then walk up from the C.f object to its defining class:

    >>> C.f.im_class
    <class '__main__.C'>

This possibility is gone in Python 3:

    >>> C.f.im_class
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'function' object has no attribute 'im_class'
    >>> dir(C.f)
    ['__annotations__', '__call__', '__class__', '__closure__', '__code__',
    '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__',
    '__eq__', '__format__', '__ge__', '__get__', '__getattribute__',
    '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__',
    '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__',
    '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
    '__str__', '__subclasshook__']

This limits again the introspection capabilities available to the user.
It can produce actual issues when porting software to Python 3, for
example Twisted Core where the issue of introspecting method objects
came up several times. It also limits pickling support[1].

Proposal

This PEP proposes the addition of a __qualname__ attribute to functions
and classes. For top-level functions and classes, the __qualname__
attribute is equal to the __name__ attribute. For nested classes,
methods, and nested functions, the __qualname__ attribute contains a
dotted path leading to the object from the module top-level. A
function's local namespace is represented in that dotted path by a
component named <locals>.

The repr() and str() of functions and classes is modified to use
__qualname__ rather than __name__.

Example with nested classes

>>> class C: ... def f(): pass ... class D: ... def g(): pass ... >>>
C.__qualname__ 'C' >>> C.f.__qualname__ 'C.f' >>> C.D.__qualname__
'C.D' >>> C.D.g.__qualname__ 'C.D.g'

Example with nested functions

>>> def f(): ... def g(): pass ... return g ... >>> f.__qualname__
'f' >>> f().__qualname__ 'f.<locals>.g'

Limitations

With nested functions (and classes defined inside functions), the dotted
path will not be walkable programmatically as a function's namespace is
not available from the outside. It will still be more helpful to the
human reader than the bare __name__.

As the __name__ attribute, the __qualname__ attribute is computed
statically and it will not automatically follow rebinding.

Discussion

Excluding the module name

As __name__, __qualname__ doesn't include the module name. This makes it
independent of module aliasing and rebinding, and also allows to compute
it at compile time.

Reviving unbound methods

Reviving unbound methods would only solve a fraction of the problems
this PEP solves, at a higher price (an additional object type and an
additional indirection, rather than an additional attribute).

Naming choice

"Qualified name" is the best approximation, as a short phrase, of what
the additional attribute is about. It is not a "full name" or "fully
qualified name" since it (deliberately) does not include the module
name. Calling it a "path" would risk confusion with filesystem paths and
the __file__ attribute.

The first proposal for the attribute name was to call it __qname__ but
many people (who are not aware of previous use of such jargon in e.g.
the XML specification[2]) found it obscure and non-obvious, which is why
the slightly less short and more explicit __qualname__ was finally
chosen.

References

Copyright

This document has been placed in the public domain.

[1] "pickle should support methods": http://bugs.python.org/issue9276

[2] "QName" entry in Wikipedia: http://en.wikipedia.org/wiki/QName