skip to navigation
skip to content

Python Wiki

Python Insider Blog

Python 2 or 3?

Help Fund Python

[Python resources in languages other than English]

Non-English Resources

Add an event to this calendar.

Times are shown in UTC/GMT.

Add an event to this calendar.

PEP: 3130
Title: Access to Current Module/Class/Function
Version: de6c8ce2f930
Last-Modified:  2007-05-10 22:56:48 +0000 (Thu, 10 May 2007)
Author: Jim J. Jewett <jimjjewett at gmail.com>
Status: Rejected
Type: Standards Track
Content-Type: text/plain
Created: 22-Apr-2007
Python-Version: 3.0
Post-History: 22-Apr-2007

Rejection Notice

    This PEP is rejected.  It is not clear how it should be
    implemented or what the precise semantics should be in edge cases,
    and there aren't enough important use cases given.  response has
    been lukewarm at best.


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 for __module__

    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.

        # __import__ lets you use a variable, but... it gets more
        # complicated if the module is in a package.
        __import__(__name__)

        # So just go to sys modules... and hope that the module wasn't
        # hidden/removed (perhaps for security), that __name__ wasn't
        # changed, and definitely hope that no other module with the
        # same name is now available.
        class X(object):
            pass

        import sys
        mod = sys.modules[__name__]
        mod = sys.modules[X.__class__.__module__]

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

        # XXX sys.main is still changing as draft progresses.  May
        # really need sys.modules[sys.main]
        if __module__ is sys.main:    # assumes PEP (3122), Cannon
            ...


Rationale for __class__

    Class methods are passed the current instance; from this they can
    determine self.__class__ (or cls, for class methods).
    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):
                # ?!? issubclass(D,C), so it "works":
                super(C, self).meth() 

    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 the "New Super"
    PEP (Spealman).  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.


Rationale for __function__

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

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

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

        # class exists only to provide storage:
        class _wrap(object):

            __total = 0

            def f(self):
                self.__total += 1
                return self.__total

        # set module attribute to a bound method:
        accum = _wrap().f

        # This function calls "factorial", which should be itself --
        # but the same programming styles that use heavy recursion
        # often have a greater willingness to rebind function names.
        def factorial(n):
            return (n * factorial(n-1) if n else 1)

    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():
            # Always refers to this function obj:
            __function__.total += 1
            return __function__.total

        def factorial(n):
            return (n * __function__(n-1) if n else 1)


Backwards Compatibility

    While a user could be using these names already, double-underscore
    names ( __anything__ ) 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].  This does not require any new bytecode operators; it just
    modifies the which specific sequence of existing operators gets
    run.


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.