[Python-Dev] Bring new features to older python versions

PJ Eby pje at telecommunity.com
Tue Oct 11 18:43:56 CEST 2011


On Tue, Oct 11, 2011 at 12:14 PM, Toshio Kuratomi <a.badger at gmail.com>wrote:

> This may not be the preferred manner to write decorators but it's fairly
> straightforward and easy to remember compared to, say, porting away from
> the
> with statement.
>

You can emulate 'with' using decorators, actually, if you don't mind a
nested function.  Some code from my Contextual library (minus the tests):

*def* *call_with*(ctxmgr):
    *"""Emulate the PEP 343 "with" statement for Python versions <2.5

    The following examples do the same thing at runtime::

        Python 2.5+          Python 2.4
        ------------         -------------
        with x as y:         @call_with(x)
            print y          def do_it(y):
                                 print y

    ``call_with(foo)`` returns a decorator that immediately invokes the
    function it decorates, passing in the same value that would be bound by
    the ``as`` clause of the ``with`` statement.  Thus, by decorating a
    nested function, you can get most of the benefits of "with", at a cost of
    being slightly slower and perhaps a bit more obscure than the 2.5 syntax.

    Note: because of the way decorators work, the return value (if any) of the
    ``do_it()`` function above will be bound to the name ``do_it``.  So, this
    example prints "42"::

        @call_with(x)
        def do_it(y):
            return 42

        print do_it

    This is rather ugly, so you may prefer to do it this way instead, which
    more explicitly calls the function and gets back a value::

        def do_it(y):
            return 42

        print with_(x, do_it)
    """*
    *return* with_.__get__(ctxmgr, type(ctxmgr))

*def* *with_*(ctx, func):
    *"""Perform PEP 343 "with" logic for Python versions <2.5

    The following examples do the same thing at runtime::

        Python 2.5+          Python 2.3/2.4
        ------------         --------------
        with x as y:         z = with_(x,f)
            z = f(y)

    This function is used to implement the ``call_with()`` decorator, but
    can also be used directly.  It's faster and more compact in the case where
    the function ``f`` already exists.
    """*
    inp = ctx.__enter__()
    *try*:
        retval = func(inp)
    *except*:
        *if* *not* ctx.__exit__(*sys.exc_info()):
            *raise*
    *else*:
        ctx.__exit__(None, None, None)
        *return* retval

This version doesn't handle the multi-context syntax of newer pythons, but
could probably be extended readily enough.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20111011/92c637f3/attachment.html>


More information about the Python-Dev mailing list