Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"return" in def

3 views
Skip to first unread message

Roger

unread,
Dec 28, 2008, 12:19:46 PM12/28/08
to
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

unread,
Dec 28, 2008, 12:33:19 PM12/28/08
to

returning nothing does nothing :)

Steve Holden

unread,
Dec 28, 2008, 12:38:50 PM12/28/08
to pytho...@python.org
Roger wrote:
> 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:

>>> from dis import dis
>>> def f1():
... print "hello"
...
>>> def f2():
... print "hello"
... return
...
>>> dis(f1)
2 0 LOAD_CONST 1 ('hello')
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
>>> dis(f2)
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
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/

Gerard Flanagan

unread,
Dec 28, 2008, 12:56:23 PM12/28/08
to
On Dec 28, 5:19 pm, Roger <rdcol...@gmail.com> wrote:
> 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.

Bruno Desthuilliers

unread,
Dec 28, 2008, 12:15:23 PM12/28/08
to
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.

Manish Sinha

unread,
Dec 28, 2008, 1:22:01 PM12/28/08
to pytho...@python.org, Roger
Roger wrote:
> 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

MRAB

unread,
Dec 28, 2008, 2:25:19 PM12/28/08
to pytho...@python.org
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.

Steven D'Aprano

unread,
Dec 28, 2008, 2:35:02 PM12/28/08
to
On Sun, 28 Dec 2008 12:38:50 -0500, Steve Holden wrote:

> Roger wrote:
>> 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:

...


>> 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.


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.


--
Steven

Roger

unread,
Dec 28, 2008, 3:06:25 PM12/28/08
to
> 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.
>
> --
> Steven

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

Benjamin

unread,
Dec 28, 2008, 4:36:54 PM12/28/08
to
On Dec 28, 1:35 pm, Steven D'Aprano <st...@REMOVE-THIS-

cybersource.com.au> wrote:
> 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.

Robert Kern

unread,
Dec 28, 2008, 4:57:51 PM12/28/08
to pytho...@python.org

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

John Machin

unread,
Dec 28, 2008, 5:02:03 PM12/28/08
to

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.
>>> def foo():
... for i in range(4):
... yield i
... return
...
>>> foo
<function foo at 0x00F5AF30>
>>> x = foo()
>>> x
<generator object foo at 0x00F61080>
>>> list(x)
[0, 1, 2, 3]
>>> def bar():
... 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>

John Machin

unread,
Dec 28, 2008, 5:12:11 PM12/28/08
to

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.

Roger

unread,
Dec 28, 2008, 6:11:53 PM12/28/08
to

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

Bruno Desthuilliers

unread,
Dec 29, 2008, 4:26:28 AM12/29/08
to
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')

John Machin

unread,
Dec 29, 2008, 4:59:13 AM12/29/08
to
On Dec 29, 8:26 pm, Bruno Desthuilliers <bruno.

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.

Bruno Desthuilliers

unread,
Dec 29, 2008, 7:23:08 AM12/29/08
to
John Machin a écrit :
> On Dec 29, 8:26 pm, Bruno Desthuilliers <bruno.
> 42.desthuilli...@websiteburo.invalid> wrote:
>> John Machin a écrit :
(snip)

>>> 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')
>
> 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.

Aaron Brady

unread,
Dec 29, 2008, 8:31:17 AM12/29/08
to

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.

Steven D'Aprano

unread,
Dec 29, 2008, 8:00:59 PM12/29/08
to
On Mon, 29 Dec 2008 05:31:17 -0800, Aaron Brady wrote:

> 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.


--
Steven

Aaron Brady

unread,
Dec 29, 2008, 9:18:23 PM12/29/08
to
On Dec 29, 7:00 pm, Steven D'Aprano <st...@REMOVE-THIS-

cybersource.com.au> wrote:
> On Mon, 29 Dec 2008 05:31:17 -0800, Aaron Brady wrote:
> > 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.

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.

Bruno Desthuilliers

unread,
Dec 30, 2008, 4:12:31 PM12/30/08
to
Steven D'Aprano a écrit :
(snip)

> Avoiding early exits is an over-reaction to the Bad Old Days of spaghetti
> code.

Mostly, yes. It can also be a way to help avoiding "resource leaks"
(memory or whatever) - just like try/finally blocks or the 'with'
statement in Python.

> 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.

And doesn't do the same thing (hint: you forgot a break statement). Also
and FWIW, the "single exit" golden rule (hem) comes from languages
without exception handling. So a fair comparison would be:

def find_egg(alist):
for item in alist:
if isinstance(item, Egg):
return item
return None

vs:

def find_sausage(alist):
found = None
for item in alist:
if isinstance(item, Sausage):
found = item
break
return found

Granted, this still doesn't make the second version better than the
first !-)

But:

> I don't think the claim that the version with an early exit is more
> complicated than the version without can justified.

Certainly not in this simple (simplistic ?) example. Now in C or Pascal,
functions tend to be much longer and complicated, thanks to all the gory
details one has to take care of.

Not that I'm advocating "no early return" as a "golden rule" - specially
in Python where functions tend to be short and readable -, but there
really are cases (depending on the language *and* concrete use case)
where avoiding early returns makes for more readable and robust code.

My 2 cents...

0 new messages