PEP 3155 – Qualified name for classes and functions | peps.python.org (original) (raw)
Author:
Antoine Pitrou
Status:
Final
Type:
Standards Track
Created:
29-Oct-2011
Python-Version:
3.3
Post-History:
Resolution:
Table of Contents
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:
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 "", line 1, in 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..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.