[Python-Dev] Bring new features to older python versions (original) (raw)

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