The common python pattern
def foo():
tmp = []
for x in y:
...
tmp.append(z)
return tmp
can be simplified to
@cast
def foo() -> list:
for x in y:
...
yield z
using the decorator cast
, which I have implemented here.
Some examples:
@cast
def nums() -> dict:
yield 1, 'one'
yield 2, 'two'
# {1: 'one', 2: 'two'}
@cast
def hello() -> (str.upper, ', '.join):
yield "Hello"
yield "world"
# 'HELLO, WORLD'
A decorator for function composition as follows would be useful.
compose = lambda f: lambda g: lambda *a, **k: f(g(*a, **k))
@compose(str.upper)
@compose(', '.join)
def hello():
yield "Hello"
yield "world"
However, the notation achieved by cast
is superiour.
We can nicely loop through generators using for
loops. However, for
coroutines, this is not possible, since we have no way of sending values. I
therefore suggest allowing continue
to take an optional expression to send to the generator. For example, in
for x in g:
...
continue y
the first value of x
would be obtained from next(g)
as usual, but
subsequent values are obtained from g.send(y)
(of course, allowing continue
to be used in branches as it is currently, with g.send(None)
or next(g)
used if an iteration ends without a continue).
Currently this has to be done using the more clumsy
x = next(g)
try:
while True:
...
x = g.send(y)
except StopIteration:
pass
Iterators raise StopIteration
exceptions to stop. In particular, generators
raise the exception when they return, with the value
property set to the
returned value. I suggest using the finally
keyword for accessing this as follows:
def gen():
yield 'foo'
return 'bar'
for x in gen():
print(x)
finally y:
print(y) # prints 'bar'
Supplying a variable to finally
would be optional.
This would also be useful with the else
case for for
loops: the else
case
happens if the loop ends without breaking, and the finally
case occurs
regardless. Placing the finally
case before the else
case would simplify
some code.
If the loop is terminated by break
, the value should be None
. Moreover,
break
could be extended to also take an expression to give to finally
.
for x in range(1):
break 'bar'
finally y:
print(y) # prints 'bar'
else EXPRESSION:
...
as shorthand for
else:
assert(EXPRESSION)
...
though perhaps a new exception type should be used.