Return as a decorator

Quite often we see the following idiom:

def SOME_FUNCTION(...):
  ...
return SOME_FUNCTION

This is used in a vast majority of functions that return functions.

This might be a far-fetched idea but wouldn’t this code be made clearer with:

@return
def SOME_FUNCTION(...):
  ...

It wouldn’t save any LOC, I just think it would be a clearer declaration of intent. It would make the code more readable, and would make refactoring easier. return is already a keyword, so this wouldn’t be a breaking change. But now instead of seeing a function declared and thinking “Where are they going with this?” you’ll think “OK, this is the value the function returns.”

This’ll make a lot of wrapper functions simple to implement, and will clear up a lot of ugly code

def inform_on_calls(callback: Callable):
  def actual_decorator(func):
    @wraps(foo)
    def wrapper(*args, **kwargs):
      callback()
      foo(*args, **kwargs)
    return wrapper
  return actual_decorator

Imagine if whenever users had to return a variable, they’d have to first assign it to a variable, and then return it.

With my proposal (which I fully expect to be shot down, I just want to start a discussion on that bothersome idiom), the code would be replaced with:

def inform_on_calls(pre_call: Callable):
  @return
  def _(func):
    @return
    @wraps(foo)
    def _(*args, **kwargs):
      pre_call()
      foo()

What’s so special about returning a function that it needs special
syntax that returning an int or a str or a list doesn’t get?

Decorator syntax:

@decorator
def spam(): ...  # or class statement

is syntactic sugar for:

def spam(): ...
spam = decorator(spam)

The reasons why this syntactic sugar is important and useful have been
discussed elsewhere, so I won’t go over the details, but the important
thing is that the decorator itself is an expression, not a keyword or
statement. @return doesn’t work because return is not a name that
can be looked up and dereferenced to get a callable object which can be
called.

So the interpreter would have to add a special syntax rule for @return
over and above regular decorators and regular returns. So we have a new,
special case that brings us what benefit?

There are also two additional practical problems. What happens if you
have multiple decorators? What happens if you post-process the
inner function
after you decorate it?

@functools.wraps(func)
@return
def inner(...):
    ...
inner.extra = 1234

I can see this causing a lot of errors where people forget to remove the
@return and end up with dead code that never gets called. Or at least,
I can see myself making that error,

Ben asked the rhetorical question:

"This might be a far-fetched idea but wouldn’t this code be made
clearer with:

@return
def SOME_FUNCTION(...):
  ...

"

The trouble with rhetorical questions is that often the answer isn’t as
rhetorical as one would hope. No, it wouldn’t be clearer. To me that
looks like it should be syntactic sugar for:

def SOME_FUNCTION(...):
    ...
SOME_FUNCTION = return(SOME_FUNCTION)

and now I’m confused because I know that’s impossible. If I were a
beginner who had learned about decorators, I’d probably spend some time
searching for the definition of this “return” decorator:

def return(function):
    ...

so rather than add clarity, making the return of a function a
special case obfuscates the situation by adding a special case to
decorator syntax and a special case to returns.

“It wouldn’t save any LOC, I just think it would be a clearer
declaration of intent.”

Everywhere else the @word decorator syntax declares the intent:

“decorate this function and bind it to the same name”

You are redefining it to sometimes mean:

“don’t decorate anything, just return”

I don’t think that @return is a more clear declaration of the intent
to return SOME_FUNCTION than actually saying return SOME_FUNCTION.
That’s pretty much as explicit a declaration of intent as it is possible
to have.

A syntax that may be useful (and actually implementable) would be something like

def this_returns_a_function():
    ...

    return def function_to_return():
        ...

But personally I don’t think it is any more readable than explicitly returning the function name as a variable either.