[Python-ideas] Moving return above statements [was Re: Syntax for defining parametric decorators]
Steven D'Aprano
steve at pearwood.info
Thu Jul 12 03:37:00 CEST 2012
Nick Coghlan wrote:
> On Mon, Jul 9, 2012 at 7:47 PM, Stefan Behnel <stefan_ml at behnel.de> wrote:
>> >From an innocent look, I have no idea what the syntax is supposed to mean.
>> Clearly doesn't hint at a factory for me.
>
> I should also mention that I have a different proposal that affects
> the way one would write functions-that-returns-functions. I've been
> messing around with the idea of statement local namespaces for years
> (see PEP 3150) trying to find something that I consider better than
> the status quo, and PEP 403's statement local function and class
> definitions (http://www.python.org/dev/peps/pep-0403/) are the current
> incarnation.
>
> With those, the number of statements in a simple wrapping decorator
> factory doesn't change, but the return statements can be moved above
> their respective function definitions:
>
> def notify_on_call(callback, *cb_args, **cb_kwds):
> in return decorator
> def decorator(f):
> in return wrapped
> @functools.wraps(f)
> def wrapped(*args, **kwds):
> callback(*cb_args, cb_kwds)
> return f(*args, **kwds)
I *really* don't like the way that the "in return" statement reads like it
creates a new block, but the following lines are not indented. If I were
writing this as pseudo-code for a human reader, I would surely indent the
following lines.
Even if the part following the "in return" were limited to a single
expression, I would prefer to indent it if it appears on another line. Using
lambda as an example:
# Best
lambda x: expression
# Acceptable
lambda x:\
expression
# Unacceptable
lambda x:\
expression
Looking back at "in return", here's a simple example which doesn't use nested
functions. Compare:
def function(arg):
in return value
value = process(arg)
print("Value is", value)
versus:
def function(arg, verbose=False):
in return value:
value = process(arg)
print("Value is", value)
The lack of indentation (and trailing colon) makes the first extremely
unpythonic -- everything else that creates a new block is indented.
Consequently I hate the first one and am merely cold to the second.
> Rather than the current out-of-order:
>
> def notify_on_call(callback, *cb_args, **cb_kwds):
> def decorator(f):
> @functools.wraps(f)
> def wrapped(*args, **kwds):
> callback(*cb_args, cb_kwds)
> return f(*args, **kwds)
> return wrapped
> return decorator
I would not describe that as "out-of-order". Seems to me that it is precisely
in order: first you create the object (a function), then you return it. You
can't return something before it exists.
It seems to me that this proposal, and the older PEP 3150, are the ones which
are out-of-order: you use things before they are defined.
For what it's worth, I have slightly warmed to PEP 3150 and would give it a
very tentative +0.125:
def notify_on_call(callback, *cb_args, **cb_kwds):
return decorator given:
def decorator(f):
@functools.wraps(f)
def wrapped(*args, **kwds):
callback(*cb_args, cb_kwds)
return f(*args, **kwds)
return wrapped
I don't think the above is any improvement at all on the status quo, but 3150
would allow you to write maths expressions more mathematically:
def func(x):
return a**2 + 3*a given:
a = 1/(sin(x*pi)) + (cos(x)-1)/2
which I'm not sure will help people used to reading code, but it should at
least be familiar territory to mathematicians and maths geeks.
(Aside: I actually prefer that bikeshed to be called "where" rather than "given".)
--
Steven
More information about the Python-ideas
mailing list