173 lines
4.9 KiB
ReStructuredText
173 lines
4.9 KiB
ReStructuredText
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
|
|
==========
|
|
|
|
.. [1] "pickle should support methods":
|
|
http://bugs.python.org/issue9276
|
|
|
|
.. [2] "QName" entry in Wikipedia:
|
|
http://en.wikipedia.org/wiki/QName
|
|
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
..
|
|
Local Variables:
|
|
mode: indented-text
|
|
indent-tabs-mode: nil
|
|
sentence-end-double-space: t
|
|
fill-column: 70
|
|
coding: utf-8
|
|
End:
|