views:

205

answers:

6

I'm pretty new at python and I was wondering if this:

def func(self, foo):
    for foo in self.list:
        if foo.boolfunc(): return True
    return False

is good practice.

Can I return out of a loop like the above or should i use a while-loop, like so?

def func(self, foo):  
    found = false
    while(not found & i < len(self.list)):
        found = foo.boolfunc()
        ++i
    return found

My java-professor warns us never to use breaks in our loops, but this technically isn't a break and it's more concise, so... yeah

thanks

+2  A: 

It is good practice.

My java-professor warns us never to use breaks in our loops

Why is that? “never” is a strong word in computer science and should never (…) be used.1)


1) Except for “goto” … we all have our pet peeves. ;-)

Konrad Rudolph
+1 for generalizations always being wrong
Frank
thanks!well, he says it's a bad habit that can (almost?) always be replaced with something better.
thepandaatemyface
its nearly always possible to replace a break, whether its better is a matter of opinion
jk
@jk: It's *always* possible to replace `break` with an exit condition. There's actually a proof of this, it's the "Flow of control in the proof theory of structured programming".
S.Lott
@Konrad Rudolph: For students learning to program, "never" is never strong enough. For students you always have to use absolutes, or they never understand that the edge conditions really are edge conditions.
S.Lott
@S.Lott: true, I use it as well, even on somewhat controversial topics I have to admit. But here the professor is **wrong** (i.e. not sharing my opinion). ;-)
Konrad Rudolph
always is a hard word, the caveat was in case some one defines a language that only uses break, not very useful but would contradict that sort of assertion
jk
@jk: a language that only uses break? You mean assembler? If you have no alternative to break, then the "always" is still true; if there's no alternative, it's excluded from the set *a priori*.
S.Lott
+12  A: 

There's nothing wrong with your example, but it's better to write

def func(self, foo):
    return any(foo.boolfunc() for foo in self.list)
gnibbler
thanks, i'm not familiar yet with the ins and outs of python, but stuff like this makes me want to learn more
thepandaatemyface
Docs for any(): http://docs.python.org/library/functions.html#any . Docs for generator expressions: http://docs.python.org/tutorial/classes.html#generator-expressions
codeape
+5  A: 

Your professor is advocating a practice called "Single point of Return", which basically states that any block of code should only have one point of exit. Breaks in loops are somewhat distinct from this, but usually lumped together.

It's a controversial opinion, to say the least, and certainly not as hard and fast a rule as "never use goto". It's probably worth doing it his way - you can appease him and also see the benefit of both approaches, but most people probably aren't too strict on single point of return if violating it makes their code more readable.

Ryan Brunner
A: 

"Breaking out of a loop" can easily devolve to bad practice because it conceals the terminating condition of the loop.

If your if statement is of moderate complexity, then it can become unclear what post-condition the loop establishes.

If your exit condition is obvious, then an early exit is a common syntactic optimization.

If your exit condition is not obvious, then a convoluted, nested, hard-to-follow set of if statements is doing you more harm than good.

Indeed, this SO question shows that the presence of a simple try block can lead to conditions so baffling that a clearly incorrect piece of code was produced and could not easily be debugged.

Generally, all "early-exit" things (the break statement, in particular) lead to problems creating a formal proof. (The else statement has similar problems.)

If you develop your program by reasoning out the statements required to create the necessary post-condition, you'll never need break or an early return because you can't easily create these statements using formal methods.

Also, note that any advice to avoid break or else will lead to hate mail and downvoting. For inexplicable reasons, looking closely at some programming constructs is a bad thing.

http://stackoverflow.com/questions/865741/else-considered-harmful-in-python

If the exit condition of a loop with a break (or early return) is not obvious, you need to rework things to make it obvious.

In this example, they're obvious, so there's no issue with the specific example as presented.

S.Lott
@S.Lott: how relevant do you think formal proofs are? In my experience, not at all, because even simple algorithms are much too complex, and this complexity isn’t changed by whether you use early exit or not. In fact, the loop invariant doesn’t change either way. (Not my downvote, BTW. Your point is still well made.)
Konrad Rudolph
@Konrad Rudolph: They're essential. In a reasonably usable language, the "primitives" -- statements, built-in data types, etc. -- will have proofs that these things actually work as advertised. Some proofs are very formal, others are moderately formal. But without some level of trust, then folks slowly loose confidence in the language.
S.Lott
Such formal approaches are directly at odds with the practicalities of writing lots of code, which is probably why such advice gets downvoted. Anyone who has ever tried to trace through a complex routine that uses 10 flags instead of 10 returns will -1 such advice immediately.
romkyns
To be honest, I’ve never heard that, and I rather doubt it. Sure, maths libraries will use formal proofs, and a few other things. But besides that … no big presence. In fact, remarkably few good programmers use formal proofs at all, if “Coders at Work” is any indication.
Konrad Rudolph
@romkyns: "Practicality" is not the issue. The issue is **obviously correct**. If your code is good, you don't need a formal proof of every line. If your code is bad, the formal proof mental discipline can help reduce the badness.
S.Lott
@Konrad Rudolph. Most (98%) of programmers don't use formal methods. However, when you read code for OS libraries, data structures, interpreters, etc., you will see traces of formal methods in the comments. Many, many pieces of code have been reviewed by formal methods to assure that they work as advertised. It doesn't take must effort at all to prove that a loop terminates or that the Red-Black coloring algorithm in a TreeMap actually meets all the requirements. It's easier than writing endless unit tests.
S.Lott
+6  A: 

It should be mentioned that in Python, for loops can have an else clause. The else clause is only executed when the loop terminates through exhaustion of the list.

So you could write:

def func(self):
    for foo in self.list:
        if foo.boolfunc():
            return True
    else:
        return False
codeape
+1 I didn't know that, that was really cool.
wasatz
+4  A: 

"Early exit" is a perfectly Pythonic style (when warranted: gnibbler's answer correctly points out that for your specific use case there's a built-in [[in Python 2.5 and better]] that's preferable) and often helps realize the Pythonic goal of "flat is better than nested". And for is usually the right way to do looping in Python, at application-level: if there's any complicated loop logic (as might warrant a while), it's often better to push it down to an auxiliary generator anyway.

Advantages sometimes claimed for the alternative "single point of exit" include the existence of a single "exit bottleneck" at which clean-up can be performed. But since exceptions are always possible, you don't know that your single return is a unique exit bottleneck, even if you have it: the proper way to ensure good cleanup is, instead, the with statement (in 2.6, or 2.5 with an "import from the future"; for older versions of Python, the clunkier but still useful try/finally instead).

Knuth's article "Structured Programming With Goto Statements" (pdf) -- an incredible, visionary article from 1974 by the man that many consider a living legend of computer science, both theoretical and practical -- is well worth reading. Anybody who doubts the article's applicability to Python should consider the following short quote from it:

devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language.

twenty years before Python 1.0 was published, Knuth already foresaw the key syntax aspect that was to become such a hallmark of Python (and, independently, Haskell, released a bit earlier than Python -- from personal discussion with Knuth, Peyton Jones, and van Rossum, I can attest they all claim that these three inventions of "indentation for grouping" were entirely independent from each other, just a case of "great minds think alike" -- or, in Charles Fort's words, "it was just steam engine time";-).

Formal proofs of code including early exit are of course not a jot harder than for equivalent code with single point of exit, if nothing else because the famous proof by Corrado Böhm and Giuseppe Jacopini shows how to perform a mechanical transformation from any flowchart to one containing only sequence, selection and repetition (but of course the transformed program -- just like any other program trying to avoid the early-exit style -- is prone to having more nesting than needed, and extra boolean "status" variable, which interfere with readability, directness, and efficiency -- making early-exit much superior in languages that support it well).

Alex Martelli
+1 – once again, well worth reading.
Konrad Rudolph
@Konrad, glad you liked it!-)
Alex Martelli