"return" in def

  • Thread starter Bruno Desthuilliers
  • Start date
B

Bruno Desthuilliers

Roger a écrit :
When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
# do something
return

Is this pythonic or excessive?

If it's the last statement in the function body, it is indeed "excessive".

OTHO I sometimes end a function with an explicit "return None" when
there are branches with early returns, ie:

def func():
if some_condition:
return something
return None

to make really clear what happens - even if it _should_ be clear without
the last statement. IOW : use your own judgement.
 
R

Roger

Hi Everyone,

First I want to thank everyone that posts to this group. I read it
daily and always learn something new even if I never feel like I have
anything to contribute but my questions.

When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
# do something
return

Is this pythonic or excessive? Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.

Even when I'm not explicitly returning something I like to add
"return" because it's a good additional visual marker for me to see
where a method definition ends especially in cases where I may use a
nested method.

Thanks for the discussion!
Roger.
 
R

r

Hi Everyone,

First I want to thank everyone that posts to this group.  I read it
daily and always learn something new even if I never feel like I have
anything to contribute but my questions.

When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
        # do something
        return

Is this pythonic or excessive?  Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.

Even when I'm not explicitly returning something I like to add
"return" because it's a good additional visual marker for me to see
where a method definition ends especially in cases where I may use a
nested method.

Thanks for the discussion!
Roger.

returning nothing does nothing :)
 
S

Steve Holden

Roger said:
Hi Everyone,

First I want to thank everyone that posts to this group. I read it
daily and always learn something new even if I never feel like I have
anything to contribute but my questions.

When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
# do something
return

Is this pythonic or excessive? Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.
It's an unnecessary affectation, but I don't believe it adds any clock
ticks to your app, as the function has to return anyway. The dis module
shows you they both generate exactly the same code:
.... print "hello"
........ print "hello"
.... return
.... 2 0 LOAD_CONST 1 ('hello')
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE 2 0 LOAD_CONST 1 ('hello')
3 PRINT_ITEM
4 PRINT_NEWLINE

3 5 LOAD_CONST 0 (None)
8 RETURN_VALUE
Even when I'm not explicitly returning something I like to add
"return" because it's a good additional visual marker for me to see
where a method definition ends especially in cases where I may use a
nested method.
Well, I suppose at least you aren't writing "return None" ...
Normally a blank line or two suffices for me.

Take a look at PEP 8 for some discussion for Python coding style.

http://www.python.org/dev/peps/pep-0008/

regards
Steve
 
G

Gerard Flanagan

Hi Everyone, [...]
When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
        # do something
        return

Is this pythonic or excessive?  Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.

It's not particularly excessive but it is uncommon. A nekkid return
can sometimes be essential within a function body, so a non-essential
nekkid return could be considered just noise.

G.
 
M

Manish Sinha

Roger said:
Hi Everyone,

First I want to thank everyone that posts to this group. I read it
daily and always learn something new even if I never feel like I have
anything to contribute but my questions.
Same here, I always read the news, but hardly post anything since am not
very much expert in Python.
Even when I'm not explicitly returning something I like to add
"return" because it's a good additional visual marker for me to see
where a method definition ends especially in cases where I may use a
nested method.
I would personally prefer to use a comment for return rather than giving
an explicit return statement.
e.g.
# return from function

--
Manish Sinha

Personal Blog: http://www.manishsinha.info
Tech Blog: http://manishtech.wordpress.com
OpenPGP Key: 99E6658F
 
M

MRAB

Gerard said:
Hi Everyone, [...]
When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:

def something():
# do something
return

Is this pythonic or excessive? Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.

It's not particularly excessive but it is uncommon. A nekkid return
can sometimes be essential within a function body, so a non-essential
nekkid return could be considered just noise.
If it's a function, ie the result is used by the caller, then explicitly
return with the value, even if it's None. On the other hand, if it's a
procedure, ie the result is always None and that result isn't used by
the caller, then don't use return, except for an early exit.
 
S

Steven D'Aprano

It's an unnecessary affectation, but I don't believe it adds any clock
ticks to your app, as the function has to return anyway. The dis module
shows you they both generate exactly the same code: ....
Well, I suppose at least you aren't writing "return None" ... Normally a
blank line or two suffices for me.


Curious. When I see a bare return, the first thing I think is that the
author forgot to include the return value and that it's a bug.

The second thing I think is that maybe the function is a generator, and
so I look for a yield. If I don't see a yield, I go back to thinking
they've left out the return value, and have to spend time trying to
understand the function in order to determine whether that is the case or
not.

In other words, even though it is perfectly valid Python, bare returns
always make the intent of the function less clear for me. I'm with Bruno
-- if you have a function with early exits, and you need to make the
intent of the function clear, explicitly return None. Otherwise, leave it
out altogether.
 
R

Roger

Curious. When I see a bare return, the first thing I think is that the
author forgot to include the return value and that it's a bug.

The second thing I think is that maybe the function is a generator, and
so I look for a yield. If I don't see a yield, I go back to thinking
they've left out the return value, and have to spend time trying to
understand the function in order to determine whether that is the case or
not.

In other words, even though it is perfectly valid Python, bare returns
always make the intent of the function less clear for me. I'm with Bruno
-- if you have a function with early exits, and you need to make the
intent of the function clear, explicitly return None. Otherwise, leave it
out altogether.

To me this is the soundest argument. Thanks for the advice. I think
I'll follow this as a rule of thumb hereafter.
 
B

Benjamin

The second thing I think is that maybe the function is a generator, and
so I look for a yield.

You shouldn't, though; Generators can't contain any return statement.
 
R

Robert Kern

Benjamin said:
You shouldn't, though; Generators can't contain any return statement.

Yes, they can. It doesn't return a value, it just raises a StopIteration error.

In [18]: def g():
for i in range(5):
if i == 3:
print 'Early exit.'
return
print 'Should not happen.'
yield i
....:
....:

In [25]: list(g())
Early exit.
Out[25]: [0, 1, 2]

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
J

John Machin

You shouldn't, though; Generators can't contain any return statement.

What gave you that impression?

<experimentation>

Python 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information..... for i in range(4):
.... yield i
.... return
....
.... for i in range(4):
.... yield i
.... return 42
....
File "<stdin>", line 4
SyntaxError: 'return' with argument inside generator

</experimentation>

<manual>

(go to http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy
then scroll down)

Generator functions

A function or method which uses the yield statement (see section
The yield statement) is called a generator function. Such a function,
when called, always returns an iterator object which can be used to
execute the body of the function: calling the iterator’s next() method
will cause the function to execute until it provides a value using the
yield statement. When the function executes a return statement or
falls off the end, a StopIteration exception is raised and the
iterator will have reached the end of the set of values to be
returned.

</manual>
 
J

John Machin

To me this is the soundest argument.  Thanks for the advice.  I think
I'll follow this as a rule of thumb hereafter.

Please don't. Follow MRAB's advice, with the corollary that a
generator is forced by the compiler to be a "procedure" in MRAB's
terminology.
 
R

Roger

Please don't. Follow MRAB's advice, with the corollary that a
generator is forced by the compiler to be a "procedure" in MRAB's
terminology.

Yup, this is what I took away from this discussion. Thanks!
 
B

Bruno Desthuilliers

John Machin a écrit :
Please don't. Follow MRAB's advice, with the corollary that a
generator is forced by the compiler to be a "procedure" in MRAB's
terminology.

I fail to see any *practical* difference between MRAB's and Steven's
POVs. In both cases, it boils down to
- don't use a bare return at the end of a def statement's body,
- either use only bare returns ('procedure') or explicitely return None
('function')
 
J

John Machin

John Machin a écrit :





I fail to see any *practical* difference between MRAB's and Steven's
POVs. In both cases, it boils down to
- don't use a bare return at the end of a def statement's body,
- either use only bare returns ('procedure') or explicitely return None
('function')

Steven's treatment was somewhat discursive, and didn't explicitly
mention the 'procedure' possibility. In fact, this sentence "if you
have a function with early exits, and you need to make the intent of
the function clear, explicitly return None." would if applied to a
'procedure' cause a stylistic horror as bad as a bare return at the
end of the def.
 
B

Bruno Desthuilliers

John Machin a écrit :
Steven's treatment was somewhat discursive, and didn't explicitly
mention the 'procedure' possibility. In fact, this sentence "if you
have a function with early exits, and you need to make the intent of
the function clear, explicitly return None." would if applied to a
'procedure' cause a stylistic horror as bad as a bare return at the
end of the def.

Ok. You're right.
 
A

Aaron Brady

Hi Everyone, [...]
When I define a method I always include a return statement out of
habit even if I don't return anything explicitly:
def something():
        # do something
        return
Is this pythonic or excessive?  Is this an unnecessary affectation
that only adds clock ticks to my app and would I be better off
removing "returns" where nothing is returned or is it common practice
to have returns.

It's not particularly excessive but it is uncommon. A nekkid return
can sometimes be essential within a function body, so a non-essential
nekkid return could be considered just noise.

One style of coding I heard about once only permits returns at the end
of a function. It claims it makes it easier to see the function as a
mathematical object.

It's a slick idea, but multiple exit points are really practical.

Incidentally, generators have multiple entry points. They "yield
multiple times, they have more than one entry point and their
execution can be suspended" -- http://docs.python.org/reference/expressions..html#yield-expressions

The discussion makes me think that 'clear' is subjective, just like
'natural' has 39 definitions.
 
S

Steven D'Aprano

One style of coding I heard about once only permits returns at the end
of a function. It claims it makes it easier to see the function as a
mathematical object.

That's silly. You treat the function as a black box: input comes in, and
output comes out. You have no idea of what happens inside the black box:
it could loop a thousand times, take 150 different branches, or take one
of 37 different exit points. From the outside, it's still exactly like a
mathematical object. Internal complexity is irrelevant. This is why
mathematicians can perform algebra on complicated functions like Bessel's
function (of the first or second kind), without needing to care that
actually calculating Bessel's function is quite tricky.

What I think the one-return-per-function style is aiming at is that it is
(sometimes) easier to analyse the internals of the function if there are
few branches. The more complicated branches you have, the harder it is to
analyse the function. Early exits on their own are not the cause of the
complexity: it's the number of branches leading to the early exit that
causes the problem.

Avoiding early exits is an over-reaction to the Bad Old Days of spaghetti
code. But used wisely, early exists can simplify, not complicate, code.

Consider the following:

def find_ham(alist):
for item in alist:
if isinstance(item, Ham):
return item
raise ValueError('no ham found')


def find_spam(alist):
found_item = None
for item in alist:
if found_item is not None:
if isinstance(item, Spam):
found_item = item
if found_item is None:
raise ValueError('no spam found')
else:
return found_item


The second version has double the number of lines of code of the first.
It introduces an extra variable "found_item" and two extra if blocks. I
don't think the claim that the version with an early exit is more
complicated than the version without can justified.
 
A

Aaron Brady

That's silly. You treat the function as a black box: input comes in, and
output comes out. You have no idea of what happens inside the black box:
it could loop a thousand times, take 150 different branches, or take one
of 37 different exit points. From the outside, it's still exactly like a
mathematical object. Internal complexity is irrelevant. This is why
mathematicians can perform algebra on complicated functions like Bessel's
function (of the first or second kind), without needing to care that
actually calculating Bessel's function is quite tricky.

What I think the one-return-per-function style is aiming at is that it is
(sometimes) easier to analyse the internals of the function if there are
few branches. The more complicated branches you have, the harder it is to
analyse the function. Early exits on their own are not the cause of the
complexity: it's the number of branches leading to the early exit that
causes the problem.

You'd think they would have noticed that. Eliminating early exits
doesn't change the number of branches!
Avoiding early exits is an over-reaction to the Bad Old Days of spaghetti
code. But used wisely, early exists can simplify, not complicate, code.

To make your case, you don't even need to prove that a wise early exit
can simplify. You just need that an early exit can simplify. (The
conclusive case is the early exit is better. For that, it's
sufficient but not necessary to show that simplicity is your reader's
highest priority. What's instructive about that is the
counterexample: when is simpler not better? (Not rhetorical. Or, if
never, then it's the top priority and consistent with every top
priority, if my calculations are correct; but it remains to show that
early exits can simplify.)

snip better simpler
The second version has double the number of lines of code of the first.
It introduces an extra variable "found_item" and two extra if blocks. I
don't think the claim that the version with an early exit is more
complicated than the version without can justified.

In a lab report, this is the part where the author would be arguing,
"And the object accelerated at 9.8 m/s^2, which proves our
hypothesis." I think you're showing that early exits can simplify,
but you're bringing in more factors. I think you're trying to say
that less lines of code is simpler, and less variables is simpler.
Those lack proofs.

You need:
M: Less lines of code is simpler.
m: Simpler is always better.
C: Less lines of code is better.

Or something. But no amount of thrashing, bludgeoning, wibbling,
whimpering, or beating children with blunt objects, is going to change
your reader's knowledge of good. Only experience is. Fine fine, so
leather belts are bad. That doesn't make fewer lines of code good.

However, the burden of proof is (definitely IMO) on the people that
are unilaterally opposed to early returns. They need:
M: Early exits are never simpler.
m: Simpler is always better.
C: Early exits are never better.

Oddly enough, you share a minor premise.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top