Dear Python Developers,
 
We have a potential idea for enhancing Python. You will find a kind of draft bellow.
 
Best regards,
Daniel Bershatsky
 
 
Abstract
========
 
This PEP proposes the introduction of new syntax to create community standard,
readable and clear way to defered function execution in basic block on all
control flows.
 
Proposal
========
 
There is not any mechanism to defer the execution of function in python. In
order to mimic defer statement one could use either try/except construction or
use context manager in with statement.
 
We suggest to introduce defer statement to defer the execution of functions
until function returns.
 
```python
    def foo(i):
        print(i)
 
    def bar():
        defer foo(42)
        print(3.14)
 
    bar()
```
 
In code bellow execution result was
 
```
    3.14
    42
```
 
The reason is function foo is marked with defer keyword and it is not called
immediatly. In fact Python VM invokes print function before foo function which
is called on returning from bar function. Important to note that argument of
foo function must be evaludated on defer statent appered.
 
```python
    def foo(i):
        print(i)
 
    def bar():
        defer foo(42)
        if True:
            print(2.18)
            return
        print(3.14)
 
    bar()
```
 
Since defer statement is executed after function returns, output is
 
```
    2.18
    42
```
 
Another side of defer statement is order of invokation of defered functions.
In example bellow baz function contains defer calls of foo and bar
corespondently but order of actual invokation is reversed. On returning from
baz function bar function is called first and then bar function.
 
```python
    def foo():
        print(1)
 
    def bar():
        print(2)
 
    def baz():
        defer foo()
        defer bar()
 
    baz()
```
The output is
 
```
    2
    1
```
 
Rationale
=========
 
There are two the most common examples of usefull usage of defer calls based
on source code of Python 3.5.2 standard lib.
 
multiprocessing/queues.py:101-111 part of Queue.get()
 
```python
    try:
        if block:
            timeout = deadline - time.time()
            if timeout < 0 or not self._poll(timeout):
                raise Empty
        elif not self._poll():
            raise Empty
        res = self._recv_bytes()
        self._sem.release()
    finally:
        self._rlock.release()
```
 
In this piece of code try/finally is used only to release lock in any
execution branches dispite of raise exeption. By introducing defer statement
we can ensure that the lock are always released, remove extra intendation and
make code block more straight.
 
urllib/request.py:1732-1771 part of URLopener.retrive()
 
```python
    fp = self.open(url, data)
    try:
        headers = fp.info()
        if filename:
            tfp = open(filename, 'wb')
        else:
            import tempfile
            garbage, path = splittype(url)
            garbage, path = splithost(path or "")
            path, garbage = splitquery(path or "")
            path, garbage = splitattr(path or "")
            suffix = os.path.splitext(path)[1]
            (fd, filename) = tempfile.mkstemp(suffix)
            self.__tempfiles.append(filename)
            tfp = os.fdopen(fd, 'wb')
        try:
            result = filename, headers
            if self.tempcache is not None:
                self.tempcache[url] = result
            bs = 1024*8
            size = -1
            read = 0
            blocknum = 0
            if "content-length" in headers:
                size = int(headers["Content-Length"])
            if reporthook:
                reporthook(blocknum, bs, size)
            while 1:
                block = fp.read(bs)
                if not block:
                    break
                read += len(block)
                tfp.write(block)
                blocknum += 1
                if reporthook:
                    reporthook(blocknum, bs, size)
        finally:
            tfp.close()
    finally:
        fp.close()
```
 
This is the most awkward argument in favor of defer keyword. Nested
try/finally blocks can be easily replaced with only two lines of code
 
```python
    defer fp.close()
    defer tfp.close()
```
 
Also there is more synthetic pattern that replace with statement. For example,
 
```bash
    with open(filename) as fin:
        # some stuff
```
 
Or with usage defer keyword
 
```
    fin = open(filename)
    defer fin.close()
    # some stuff
```
 
Implementation
==============
 
Introduction defer statement requires modifying gramar file to parse for new
keyword. Also changes to Python.asdl, ast.c, compile.c is needed. Probably to
adopt defer statement one should modify callable implementation.
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to