Python’s introspection facilities have long had poor support fornested classes. Given a class object, it is impossible to knowwhether it was defined inside another class or at module top-level;and, if the former, it is also impossible to know in which class itwas defined. While use of nested classes is often considered poorstyle, the only reason for them to have second class introspectionsupport is a lousy pun.
Python 3 adds insult to injury by dropping what was formerly known asunbound methods. In Python 2, given the following definition:
classC:deff():pass
you can then walk up from theC.f object to its defining class:
>>>C.f.im_class<class '__main__.C'>
This possibility is gone in Python 3:
>>>C.f.im_classTraceback (most recent call last): File"<stdin>", line1, 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 theuser. It can produce actual issues when porting software to Python 3,for example Twisted Core where the issue of introspecting methodobjects came up several times. It also limits pickling support[1].
This PEP proposes the addition of a__qualname__ attribute tofunctions and classes. For top-level functions and classes, the__qualname__ attribute is equal to the__name__ attribute. Fornested classes, methods, and nested functions, the__qualname__attribute contains a dotted path leading to the object from the moduletop-level. A function’s local namespace is represented in that dottedpath by a component named<locals>.
The repr() and str() of functions and classes is modified to use__qualname__ rather than__name__.
>>>classC:...deff():pass...classD:...defg():pass...>>>C.__qualname__'C'>>>C.f.__qualname__'C.f'>>>C.D.__qualname__'C.D'>>>C.D.g.__qualname__'C.D.g'
>>>deff():...defg():pass...returng...>>>f.__qualname__'f'>>>f().__qualname__'f.<locals>.g'
With nested functions (and classes defined inside functions), thedotted path will not be walkable programmatically as a function’snamespace is not available from the outside. It will still be morehelpful to the human reader than the bare__name__.
As the__name__ attribute, the__qualname__ attribute is computedstatically and it will not automatically follow rebinding.
As__name__,__qualname__ doesn’t include the module name. Thismakes it independent of module aliasing and rebinding, and also allows tocompute it at compile time.
Reviving unbound methods would only solve a fraction of the problems thisPEP solves, at a higher price (an additional object type and an additionalindirection, rather than an additional attribute).
“Qualified name” is the best approximation, as a short phrase, of what theadditional attribute is about. It is not a “full name” or “fully qualifiedname” since it (deliberately) does not include the module name. Callingit a “path” would risk confusion with filesystem paths and the__file__attribute.
The first proposal for the attribute name was to call it__qname__ butmany people (who are not aware of previous use of such jargon in e.g. theXML specification[2]) found it obscure and non-obvious, which is why theslightly less short and more explicit__qualname__ was finally chosen.
This document has been placed in the public domain.
Source:https://github.com/python/peps/blob/main/peps/pep-3155.rst
Last modified:2025-02-01 08:59:27 GMT