[Python-ideas] with expression

אלעזר elazarg at gmail.com
Thu Feb 20 19:54:11 CET 2014


What I'd personally like to see is a combined for-with, something like

    x = [x.split() for x with in open(thisfile)]

and

    for x with in open(somefile):
        print(x)

A with expression might help too,

---
Elazar


2014-02-20 20:50 GMT+02:00 Yann Kaiser <kaiser.yann at gmail.com>:

> As an alternative to the recently-proposed "except expression", I
> suggested this in its thread. I was recommended to post this
> separately, as, while it is related, it is different enough from the
> original idea.
>
> The general idea is to extend the context manager protocol so that it
> can produce a return value in alternative to simply letting or denying
> an exception from propagating, and introduce an inline form of "with".
>
> The motivation behind is, in all honesty, that I find the suggested
> except-expressions from PEP 463 to be too verbose to inline, and that
> context managers have a much broader reach. The motivation from the
> aforementioned PEP(inline evaluation to a "default" expression upon
> catching an exception) also applies here.
>
> It could look a bit like this:
>
>     contexted_expr with context_manager as c
>
> Once more, the rationale from PEP 463 also applies here, in that we
> can shift "easy defaulting" from being a potential concern for the
> callee to being always available to the caller through new syntax.
> Likewise, currently in-lining the use of a context manager can be
> done, but only through manually encapsulating what would be the
> context-ed code through lambdas or eval.
>
> A full example could be as such:
>
>     class Default(object):
>         """Context manager that returns a given default value when an
> exception
>         is caught."""
>
>         def __init__(self, value, *exception_types):
>             self.value = value
>             self.exception_types = exception_types or BaseException
>
>         def __enter__(self):
>             pass
>
>         def __exit__(self, typ, val, tb):
>             if typ and issubclass(typ, self.exception_types):
>                 return True, self.value
>
>
>     lst = [1, 2]
>     # found is assigned 2
>     found = lst[1] with Default(0, IndexError)
>     # not found is assigned 0
>     not_found = lst[2] with Default(0, IndexError)
>
> The different interpretation of __exit__'s return value is probably
> something that needs to be discussed. In this form, it is potentially
> backwards-incompatible, so a preferable alternative would be a
> different special method, perhaps:
>
>     def __return__(self, typ, val, tb, ret):
>         if typ is None:
>             return False, ret * 3
>         elif isinstance(typ, IndexError):
>             return True, 10
>
> The alternatively-named special method would take priority over
> __exit__ and take over its augmented function:
> If no exception has occurred, typ, val, and tb are given None, as with
> the regular __exit__ incarnation, but ret, or whatever is the fourth
> positional parameter, is supplied with what "expr" evaluated to in
> "expr with cmgr". When an exception has occurred or propagated, typ,
> val and tb are set to the appropriate values(Since exceptions now keep
> their traceback as an attribute, maybe only supply the exception
> object?), and ret is given None.
> If the return value of this special method is None, the exception or
> return value is propagated as is. If it is a sequence, the first
> element is used like the return value of __exit__ would be, and the
> second element is used to (re-)place the return value of the whole
> with expression. When multiple context managers are being chained, the
> return value/exception is forwarded much like it is with twisted's
> Deferreds.
>
> In the use case of providing a default value, if the default value is
> the product of an expensive operation, an alternative context manager
> can be designed to compute the value only when needed, for instance:
>
>     fa = factorials[n] with SetDefault(factorials, n, lambda:
> math.factorial(n))
>
> Other examples using existing context managers:
>
>     contents = f.read() with open('file') as f
>
>     with open('file') as f:
>         contents = f.read()
>
>
>
>     d = Decimal(1) / Decimal(7) with Context(prec=5)
>
>     with Context(prec=5):
>         d = Decimal(1) / Decimal(7)
>
> I think that's all I can think of so far. Sorry as this might be a
> little too detailed to start with, so I will remind you there is no
> offense in rethinking any of what I posted here.
>
> -yk
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20140220/39ea8572/attachment-0001.html>


More information about the Python-ideas mailing list