[Python-Dev] PEP 30xx: Access to Module/Class/Function Currently Being Defined (this)

Jim Jewett jimjjewett at gmail.com
Mon Apr 23 05:05:14 CEST 2007


(Please note that several groups were Cc'd.  For now, please limit
followups to python-3000.  This would *probably* be backported to 2.6,
but that wouldn't be decided until the implementation strategy was
settled.)

PEP: 30XX
Title: Access to Module/Class/Function Currently Being Defined (this)
Version: $Revision$
Last-Modified: $Date$
Author: Jim J. Jewett <jimjjewett at gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 22-Apr-2007
Python-Version: 3.0
Post-History: 22-Apr-2007


Abstract

    It is common to need a reference to the current module, class,
    or function, but there is currently no entirely correct way to
    do this.  This PEP proposes adding the keywords __module__,
    __class__, and __function__.


Rationale

    Many modules export various functions, classes, and other objects,
    but will perform additional activities (such as running unit tests)
    when run as a script.  The current idiom is to test whether the
    module's name has been set to magic value.

        if __name__ == "__main__": ...

    More complicated introspection requires a module to (attempt to)
    import itself.  If importing the expected name actually produces
    a different module, there is no good workaround.

    Proposal:  Add a __module__ keyword which refers to the module
    currently being defined (executed).  (But see open issues.)

        if __module__ is sys.main: ...   # assuming PEP 3020, Cannon


    Class methods are passed the current instance; from this they can
    determine self.__class__ (or cls, for classmethods).  Unfortunately,
    this reference is to the object's actual class, which may be a
    subclass of the defining class.  The current workaround is to repeat
    the name of the class, and assume that the name will not be rebound.

        class C(B):
            def meth(self):
                super(C, self).meth() # Hope C is never rebound.

        class D(C):
            def meth(self):
                super(C, self).meth() # ?!? issubclass(D,C), so it "works"

    Proposal:  Add a __class__ keyword which refers to the class currently
    being defined (executed).  (But see open issues.)

        class C(B):
            def meth(self):
                super(__class__, self).meth()

    Note that super calls may be further simplified by PEP 30XX, Jewett.
    The __class__ (or __this_class__) attribute came up in attempts to
    simplify the explanation and/or implementation of that PEP, but was
    separated out as an independent decision.

    Note that __class__ (or __this_class__) is not quite the same as the
    __thisclass__ property on bound super objects.  The existing
    super.__thisclass__ property refers to the class from which the Method
    Resolution Order search begins.  In the above class D, it would refer to
    (the current reference of name) C.


    Functions (including methods) often want access to themselves,
    usually for a private storage location.  While there are several
    workarounds, all have their drawbacks.

        def counter(_total=[0]):   # _total shouldn't really appear in the
            _total[0] += 1         # signature at all; the list wrapping and
            return _total[0]       # [0] unwrapping obscure the code

        @annotate(total=0)
        def counter():
            counter.total += 1    # Assume name counter is never rebound
            return counter.total

        class _wrap(object):  # class exists only to provide storage
            __total=0
            def f(self):
                self.__total += 1
                return self.__total
        accum=_wrap().f       # set module attribute to a bound method

    Proposal:  Add a __function__ keyword which refers to the function
    (or method) currently being defined (executed).  (But see open issues.)

        @annotate(total=0)
        def counter():
            __function__.total += 1    # Always refers to this function obj
            return __function__.total


Backwards Compatibility

    While a user could be using these names already, __anything__ names
    are explicitly reserved to the interpreter.  It is therefore acceptable
    to introduce special meaning to these names within a single feature
    release.


Implementation

    Ideally, these names would be keywords treated specially by the bytecode
    compiler.

    Guido has suggested [1] using a cell variable filled in by the metaclass.

    Michele Simionato has provided a prototype using bytecode hacks [2].


Open Issues

    - Are __module__, __class__, and __function__ the right names?
      In particular, should the names include the word "this", either as
      __this_module__, __this_class__, and __this_function__, (format
      discussed on the python-3000 and python-ideas lists) or as
      __thismodule__, __thisclass__, and __thisfunction__ (inspired by,
      but conflicting with, current usage of super.__thisclass__).

    - Are all three keywords needed, or should this enhancement be limited
      to a subset of the objects?  Should methods be treated separately from
      other functions?


References

    [1] Fixing super anyone?  Guido van Rossum
        http://mail.python.org/pipermail/python-3000/2007-April/006671.html

    [2] Descriptor/Decorator challenge,  Michele Simionato
        http://groups.google.com/group/comp.lang.python/browse_frm/thread/a6010c7494871bb1/62a2da68961caeb6?lnk=gst&q=simionato+challenge&rnum=1&hl=en#62a2da68961caeb6


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:


More information about the Python-Dev mailing list