Avoid extra line for return

I am seeing this kind of pattern again and again which always uses one additional line for return

def func1(x):
  if x > 1:
    return
  print(x)
  ...
  (rest of function)
  ...
def func2(y):
  if len(y) < 2:
    return
  print(y)
  ...
  (rest of function)
  ...

could I achieve the same in one line?

  1. gives error
def func(x):
  return None if x > 1
  print(x)
  1. works, but after the return line the function is not executed
def f():
  return None if 1 == 2 else print(10)
  print(20)

10

(20 did not get printed, the execution ended on the return line)

I would want something like,

def func(x):
  return None if x > 1 else [someway to continue in the function]

You can put the return after the : of the if.
Personally I like the use of a separate line as I find it easier to read.

2 Likes

that leads to pylint issue

C0321: More than one statement on a single line (multiple-statements)

would not like pylint issues

And that would make Barry happy that pylint prefers the two line version :smile:

1 Like

I have a twenty-line function, and four of those lines are these return statements.
I think so there should be a way to avoid lines which have only return written in them.

It looks to me like you want a way to specify preconditions which must be fulfilled before your function is executed. One way to achieve this is with a decorator:

from functools import wraps
from typing import Callable, List


def check_preconditions(preconditions: List[Callable]):
    def decorator(f: Callable):
        @wraps(f)
        def f_new(*args, **kwargs):
            for precond in preconditions:
                if not precond(*args, **kwargs):
                    return
            return f(*args, **kwargs)

        return f_new

    return decorator

You would then use it like this:

@check_preconditions([lambda x: x > 1, lambda x: x < 3])
def f(x):
    return x


print(f(0))
print(f(1))
print(f(2))
print(f(3))

# prints None, None, 2, None

But I admit it is probably overkill if you only need these checks four times in a single function.

2 Likes

How is the interpreter supposed to know to return early from the function, if you don’t include a return statement?

If you really, really don’t want the return statement on its own line, you can include it after the colon: if condition: return.

If the linter complains, that’s a sign that most people think that what you are doing is bad style. Either obey the linter, or disable that check.

1 Like

Disable the pylint complaint, and your problem vanishes.

1 Like

this thing could work for some function, but in the function I use, none of those four are preconditions, the variables are evaluated in the function, and then I write a if statement, and then return if it satisifies.

it appears to be a problem with how return works in the background, maybe it is similar to how break, continue work, therefore, cannot execute lines after it.

plus I want the return to be avoided, that is,

def func(x):
  return None if x > 1 else [someway to continue in the function]
  ...
  (rest of function)
  ...

there should be a way to not execute the return despite using return as the first word in a line

something like a avoid keyword, which works like,

def f(x):
  return 1 if x > 1 else avoid
  ...
  (continues execution of rest of the function if the condition is not met)
  ...

or similar for break, continue also,

for i in [1, 2, 3]:
  break if i == 2 else avoid
  ...
  (for i = 1, would execute the entire for loop, would break out \
   of the for loop when i = 2, thus, i = 3 never happens)
  ...
for i in [1, 2, 3]:
  continue if i == 2 else avoid
  ...
  (for i = 1, and i = 3, would execute the entire for loop)
  ...

Just configure your .pylintrc file to ignore PEP8 E701 if it irks you and you’re good. Situations like these are what you get in a language that doesn’t have curly braces and semicolons but that’s pretty much a deliberate design choice.

By via Discussions on Python.org at 11Sep2022 18:56:

it appears to be a problem with how return works in the background,
maybe it is similar to how break, continue work, therefore, cannot
execute lines after it.

Well, it is control flow. That’s what return does!

plus I want the return to be avoided, that is,

def func(x):
 return None if x > 1 else [someway to continue in the function]
 ...
 (rest of function)
 ...

there should be a way to avoid the return despite using return as the first word in a line

People have mentioned the:

 if condition: return

form, and that you can tell pylint to not complaint about that.

You can also go:

 def func(x):
     if condition:
         the rest of the function

so that “not condition” skips that stuff and uses the end-of-function
return. Returning in the middle, as you are doing, is called “early
return”, and sometimes discouraged because the flow to the function
result is more obscure. The tradeoff to that can be more control flow
indentation such as the if-statement above.

Remember that a lot of lint checks are style checks, and can be tuned
either to prefer some style or simply disabled. Other checks are more
semantic such as an undefine or set-and-unused variable.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

No there shouldn’t.

4 Likes

RE: Adding decorators @MyFullName

Overkill, indeed. You’ve taken what was a simple piece of code and made it (without a lot of effort) unreadable.

I think yo are a bit confused about expressions vs statements:

an expression evaluates to a value, e.g.:

x + 5

a statement does something, e.g.

`return this’

as you see, return is a staemetn, tis returns from the funtion, returning the value after it.

finally, a “ternary expression”:

x if this else that

is an expression – it evaluates to a value – in this case, either the value of x or that, depending on the truthiness of this.

So:

When you write:

`return None if x > 1 else something_else

you are writing:

“terminate the function and return the value that the follwoing expressin evaluates to” – the following expression being:

None if x > 1 else something_else

so the function will alway end here, and return either None or somthing_else.

I think the confusion is that:

if this:

is a statement, whereas:

x if this else that

while using the “if” in a similar way, is an expressions.

Anyway, you haven’t posted the full twenty line, function, so hard to tell if it can be clearnly refa tors, but:

if condition1:
    return this
if condition2:
    return that
some_more
lines_of_code

is fine – no reason to remove lines of code just for brevity.

On the other hand, some folks think returning in the middle of a function can be bad style – it’s a bit harder to see at a glance where the function ends, so you can do:

if something:
   return_value = this
elif somethign_else:
    return_value = that
else:
    a_bunch
    more_code
...
return return_value

That way there is a dingle return, at the end of the function.

HTH,

-CHB

1 Like

@vainaixr - Just to provide a little bit of context: Perl has exactly this syntax, and has had it since at least 1994 when Perl 5 was released (Perl 4 may also have had it, I can’t remember). It’s called a “statement modifier”: perlsyn - Perl syntax - Perldoc Browser . Your original example translates almost verbatim:

sub func {
  my ($x) = @_;
  return if $x > 1;
  print(x);
}

I’ve quite often wished for this syntax to be available in Python for exactly the reasons you gave in your first post. It’s perfect for highlighting the control flow, while allowing for brevity of expression.

As for whether it “looks natural” - I’d say it looks a lot more natural than the related Python construct x = 3 if y > 5 else 6, which is always jarring to me in the way it splits the two possible assignment expressions by putting the condition between them.

Anyway, just a point of history here.

2 Likes

Python is capable of the exact same “statement modifier”, with a slightly different syntax. You can even put it on one-line:

if x > 1: return

While Perl hides the control flow at the end of statement, it is actually Python which genuinely highlights it by putting it at the beginning of the line.

It is only a slight exaggeration to say that Perl’s philosophy is to never have one syntax for something when they can have five.

“What are you doing on the weekend?”

“I’m going to the zoo, if the weather is nice, otherwise I’m staying home to binge-watch David Attenborough documentaries.”

The Python ternary if operator is fine, it follows common English syntax.

That’s most definitely false. I don’t personally like the Perl syntax, but it DOES put the truly important part at the start of the line: it is capable of halting the function’s execution. That is the true control flow. Calling the “if” statement the control flow is like saying that there’s a secret “goto” in there - that is to say, technically correct (probably) and utterly useless.

It’s a conditional return statement. There’s nothing inherently wrong with focusing on the return, rather than the if. It’s on par with the way that a list comprehension focuses on the value, even when there’s some filtering going on - [x*3 for x in numbers if x % 2]

But I still don’t like the Perl syntax and don’t see a lot of value in adding it to Python.

English, even more than Perl, follows the philosophy of never having one syntax when it can have one from Greek, three from Latin, two from French, two from German (nearly identical to the Latin ones), and one that Shakespeare used a few times and became famous in quotes, even though nobody would use them outside of those specific lines.

(Only a slight exaggeration, and I’m not even sure of that.)

“What are you doing on the weekend?”

“If the weather is nice, I’ll go to the zoo, otherwise I’m staying home.”

At least as common as the syntax you describe.

“Go to the zoo or stay home, depending on whether the weather’s nice.”

Less common but viable.

1 Like

That is not at all what a statement modifier means. You can find the definition in the link that I posted.

I was talking about the control flow of the return, which is vastly more important to notice than the if in this case.

Couldn’t resist a provincial jab? That’s neither true nor helpful to the discussion.

This argument holds no water. English has dozens of constructions available for saying something like this. Python’s ternary if simply chooses one of those (not a particularly clear one, IMO).

Additionally, your David Attenborough example is incorrect, because Python doesn’t allow a full statement in its ternary if construction slots, just expressions. A corrected example (showing how awkward this actually is in English too) would be:

“My activity this weekend will be going to the zoo, if the weather is nice, otherwise staying home to binge-watch David Attenborough documentaries.”

activity = zoo if weather == nice else attenborough

The fact that your English statement won’t actually translate directly into syntactically valid Python illustrates the point:

>>> activity = zoo if weather == nice else activity = attenborough
  File "<stdin>", line 1
    activity = zoo if weather == nice else activity = attenborough
               ^
SyntaxError: cannot assign to conditional expression

Finally - I’m not sure why you’re of the opinion that x() if y is so strange, but w = x() if y else z() is perfectly clear. It seems like you might just be used to what Python has decided to offer, so it feels natural after a while. To me, they seem like unnatural language choices.

If by “unnatural language choices” you mean that the choices are made to suit the needs of a non-natural language, then yes, that’s exactly what they are :slight_smile: Natural languages like English follow completely different rules and often make different decisions. Python tries to be the best Python it can be, without worrying about whether it makes good English.

(That might seem patently obvious, but there was a movement in the 1960s-70s ish to have computer languages become more like human languages, which gave us a few utter abominations that died quiet deaths with no regrets, and a few survivors like SQL - which still make appallingly bad human languages. I mean, can you imagine trying to hold a conversation with a human using nothing but SQL-legal syntax???)

1 Like