diff --git a/pep-3155.txt b/pep-3155.txt new file mode 100644 index 000000000..ba57e6436 --- /dev/null +++ b/pep-3155.txt @@ -0,0 +1,132 @@ +PEP: 3155 +Title: Qualified name for classes and functions +Version: $Revision$ +Last-Modified: $Date$ +Author: Antoine Pitrou +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 2011-10-29 +Python-Version: 3.3 +Post-History: +Resolution: TBD + + +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 + + +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 ``__qname__`` attribute to functions +and classes. For top-level functions and classes, the ``__qname__`` +attribute is equal to the ``__name__`` attribute. For nested classed, +methods, and nested functions, the ``__qname__`` attribute contains a +dotted path leading to the object from the module top-level. + +The repr() and str() of functions and classes is modified to use ``__qname__`` +rather than ``__name__``. + +Example with nested classes +--------------------------- + +>>> class C: +... def f(): pass +... class D: +... def g(): pass +... +>>> C.__qname__ +'C' +>>> C.f.__qname__ +'C.f' +>>> C.D.__qname__ +'C.D' +>>> C.D.g.__qname__ +'C.D.g' + +Example with nested functions +----------------------------- + +>>> def f(): +... def g(): pass +... return g +... +>>> f.__qname__ +'f' +>>> f().__qname__ +'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 ``__qname__`` attribute is computed +statically and it will not automatically follow rebinding. + + +References +========== + +.. [1] "pickle should support methods": + http://bugs.python.org/issue9276 + +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: