[Python-ideas] Is this PEP-able? "with" statement inside genexps / list comprehensions

Thomas Jollans tjol at tjol.eu
Wed Aug 8 19:15:28 EDT 2018


On 30/07/18 21:15, Rudy Matela wrote:
> Hello,
> 
> Do you think it would be nice to allow with statements inside genexps or
> list comprehensions?  The functions __enter__ and __exit__ would be
> automatically called as iterables are traversed.  I am thinking of
> drafting a PEP about this.  Examples:
> 
> 
> This 
> 
> 	g = (f.read() for fn in filenames with open(fn) as f)
> 
> would be equivalent to the following use of a generator function:
> 
> 	def __gen():
> 		for fn in filenames:
> 			with open(fn) as f:
> 				yield f.read()
> 	g = __gen()


To sail around Oscar's concern, this should rather be

def __gen():
    for fn in filenames:
        with open(fn) as f:
            _v = f.read()
        yield _v

But in this case I think it'd be clearer to make it an expression rather
than a generator expression term:

    g = (f.read() with open(fn) as f for fn in filenames)

where

    _ = f.read() with open(fn) as f

is equivalent to

    with open(fn) as f:
        _ = f.read()

Currently possibly (if silly) alternative:

from functools import wraps

class with_one_use:
    def __init__(self, context):
        self.__context = context

    def __getattr__(self, name):
        exc1 = False
        obj = self.__context.__enter__()
        try:
            temp = getattr(obj, name)
        except:
            exc1 = True
            if not self.__context.__exit__(*sys.exc_info()):
                raise
        else:
            if callable(temp):
                @wraps(temp)
                def f(*args, **kwargs):
                    exc2 = False
                    try:
                        return temp(*args, **kwargs)
                    except:
                        exc2 = True
                        if not self.__context.__exit__(*sys.exc_info()):
                            raise
                    finally:
                        if not exc2:
                            self.__context.__exit__(None, None, None)
                exc1 = True
                return f
            else:
                return temp
        finally:
            if not exc1:
                self.__context.__exit__(None, None, None)


g = (with_one_use(open(fn)).read() for fn in filenames)


-- Thomas

> 
> 
> This
> 
> 	list = [f.read() for fn in filenames with open(fn) as f]
> 
> would be equivalent to the following:
> 
> 	list = []
> 	for fn in filenames:
> 		with open(fn) as f:
> 			list.append(f.read())
> 
> --
> Rudy
> _______________________________________________
> 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/
> 



More information about the Python-ideas mailing list