Re: If/then style question
I'd bet you would stress your point Steven! But you don't need to persuade me, I do already agree. I just meant to say that, when the advantage is little, there's no need to rewrite a working function. And that with modern CPUs, if tests take so little time, that even some redundant one is not so much of a nuisance. in your working example, the "payload" is just a couple of integer calculations, that take very little time too. So the overhead due to redundant if tests does show clearly. And also in that not-really-real situation, 60% overhead just meant less than 3 seconds. Just for the sake of discussion, I tried to give both functions some plough to pull, and a worst-case situation too: >>> t1 = Timer('for x in range(100): print func1(0),', ... 'from __main__ import func1') >>> >>> t2 = Timer('for x in range(100): print func2(0),', ... 'from __main__ import func2') >>> >>> min(t1.repeat(number=1, repeat=1)) -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 53.011015366479114 >>> min(t2.repeat(number=1, repeat=1)) -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 47.55442856564332 that accounts for a scant 11% overhead, on more than one million tests per cycle. That said, let's make really clear that I would heartily prefer func2 to func1, based both on readability and speed. Thank you for having spent some time playing with me! Francesco On 19/12/2010 1.05, Steven D'Aprano wrote: Well, let's try it with a working (albeit contrived) example. This is just an example -- obviously I wouldn't write the function like this in real life, I'd use a while loop, but to illustrate the issue it will do. def func1(n): result = -1 done = False n = (n+1)//2 if n%2 == 1: result = n done = True if not done: n = (n+1)//2 if n%2 == 1: result = n done = True if not done: n = (n+1)//2 if n%2 == 1: result = n done = True if not done: for i in range(100): if not done: n = (n+1)//2 if n%2 == 1: result = n done = True return result def func2(n): n = (n+1)//2 if n%2 == 1: return n n = (n+1)//2 if n%2 == 1: return n n = (n+1)//2 if n%2 == 1: return n for i in range(100): n = (n+1)//2 if n%2 == 1: return n return -1 Not only is the second far more readable that the first, but it's also significantly faster: from timeit import Timer t1 = Timer('for i in range(20): x = func1(i)', ... 'from __main__ import func1') t2 = Timer('for i in range(20): x = func2(i)', ... 'from __main__ import func2') min(t1.repeat(number=10, repeat=5)) 7.3219029903411865 min(t2.repeat(number=10, repeat=5)) 4.530779838562012 The first function does approximately 60% more work than the first, all of it unnecessary overhead. -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Sat, 18 Dec 2010 19:59:45 -0800, Carl Banks wrote: > On Dec 17, 12:23 am, Steven D'Aprano +comp.lang.pyt...@pearwood.info> wrote: >> On Thu, 16 Dec 2010 20:32:29 -0800, Carl Banks wrote: >> > Even without the cleanup issue, sometimes you want to edit a function >> > to affect all return values somehow. If you have a single exit point >> > you just make the change there; if you have mulitple you have to hunt >> > them down and change all of them--if you remember to. I just got bit >> > by that one. >> >> If your function has so many exit points that you can miss some of them >> while editing, your function is too big, does too much, or both. > > Sanctimonious much? In the real world, people "miss things" and "make > mistakes" and not necessarily because they are working on something too > complex to handle. It happens. Really? I had no idea. I've never made a misteak, I asumed evrybody else was equally brilliant. No, wait, there was that one time... *wink* Of course people make mistakes. So what's your point? The point I was trying to make is that rather than encouraging an idiom (only one return statement, even if the algorithm is more clearly written with multiple exists) that leads to more complex, less efficient code just in case you might someday need to modify the return result, there are simple alternatives that avoid the need for anti-patterns like copy- and-paste coding or enforced single exit point. I gave two: - refactor the complex code so that it's less complex (e.g. instead of 20 exit points, which makes it easy to miss one or two, refactor it so there are two or three exit points); or if that's not practical: - wrap it in a decorator that performs the post-processing you need. Both can be simple, effective and Pythonic. Neither require the coder to use an artificial idiom just in case of some future need. The decorator solution works even if you don't have access to the source code, or if the function is a complex black box that nobody understands well enough to touch. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Dec 17, 12:23 am, Steven D'Aprano wrote: > On Thu, 16 Dec 2010 20:32:29 -0800, Carl Banks wrote: > > Even without the cleanup issue, sometimes you want to edit a function to > > affect all return values somehow. If you have a single exit point you > > just make the change there; if you have mulitple you have to hunt them > > down and change all of them--if you remember to. I just got bit by that > > one. > > If your function has so many exit points that you can miss some of them > while editing, your function is too big, does too much, or both. Sanctimonious much? In the real world, people "miss things" and "make mistakes" and not necessarily because they are working on something too complex to handle. It happens. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Sat, 18 Dec 2010 12:29:31 +0100, Francesco wrote: [...] > I agree to your point, but I'm afraid you chose a wrong example (AFAIK, > and that's not much). Sure, the second version of function(arg) is much > more readable, but why do you think the first one would do "*lots* of > unnecessary work"? > All the overhead in that function would be: >if some_condition, three IF tests, and you know that's NOT a lot! Well, let's try it with a working (albeit contrived) example. This is just an example -- obviously I wouldn't write the function like this in real life, I'd use a while loop, but to illustrate the issue it will do. def func1(n): result = -1 done = False n = (n+1)//2 if n%2 == 1: result = n done = True if not done: n = (n+1)//2 if n%2 == 1: result = n done = True if not done: n = (n+1)//2 if n%2 == 1: result = n done = True if not done: for i in range(100): if not done: n = (n+1)//2 if n%2 == 1: result = n done = True return result def func2(n): n = (n+1)//2 if n%2 == 1: return n n = (n+1)//2 if n%2 == 1: return n n = (n+1)//2 if n%2 == 1: return n for i in range(100): n = (n+1)//2 if n%2 == 1: return n return -1 Not only is the second far more readable that the first, but it's also significantly faster: >>> from timeit import Timer >>> t1 = Timer('for i in range(20): x = func1(i)', ... 'from __main__ import func1') >>> t2 = Timer('for i in range(20): x = func2(i)', ... 'from __main__ import func2') >>> min(t1.repeat(number=10, repeat=5)) 7.3219029903411865 >>> min(t2.repeat(number=10, repeat=5)) 4.530779838562012 The first function does approximately 60% more work than the first, all of it unnecessary overhead. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 17/12/2010 0.51, Steven D'Aprano wrote: Don't get me wrong... spaghetti code is*bad*. But there are other ways of writing bad code too, and hanging around inside a function long after you've finished is also bad: def function(arg): done = False do_something() if some_condition: result = "finished" done = True if not done: do_something_else() if another_condition: result = "now we're finished" done = True if not done: do_yet_more_work() if third_condition: result = "finished this time for sure" done = True if not done: for i in range(100): if not done: do_something_small() if yet_another_condition: result = "finally done!" done = True return result It's far more complicated than it need be, and does*lots* of unnecessary work. This can be written more simply and efficiently as: def function(arg): do_something() if some_condition: return "finished" do_something_else() if another_condition: return "now we're finished" do_yet_more_work() if third_condition: return "finished this time for sure" for i in range(100): do_something_small() if yet_another_condition: return "finally done!" I agree to your point, but I'm afraid you chose a wrong example (AFAIK, and that's not much). Sure, the second version of function(arg) is much more readable, but why do you think the first one would do "*lots* of unnecessary work"? All the overhead in that function would be: if some_condition, three IF tests, and you know that's NOT a lot! if no conditions were met, (worst case) the first version would return an exception (unless result was globally defined) while the second would happily return None. Apart from this, the overhead in the first one would amount to one million IF tests, again not a lot these days. I don't think I would rewrite that function, if I found it written in the first way... I don't mean that the fist example is better, just I'm sure you could imagine a more compelling proof of your concept. Maybe there's something I don't know... in that case, please enlighten me! Francesco -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Fri, 17 Dec 2010 17:26:08 +, Grant Edwards wrote: > Give me code that's easy-to-read and doesn't work rather code that works > and can't be read any day. Well, in that case, you'll love my new operating system, written in 100% pure Python: [start code] print("this is an operating system") [end code] I expect it to rapidly make Windows, Linux and OS-X all obsolete. Bill Gates and Steve Jobs, look out! *grin* Surely your attitude towards usefulness vs. readability will depend strongly on whether you are intending to *use* the code, or *maintain* the code? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Fri, 17 Dec 2010 10:53:45 -0500, Steve Holden wrote about for...else: > This construct appears to be unpopular in actual use, and when it comes > up in classes and seminars there is always interesting debate as people > discuss potential uses and realise there are useful applications. Yes, I find I don't need it often, but it is useful from time to time. I wonder whether it would have been more useful to reverse the sense of the else, and have it run only if the for loop *didn't* run to completion. That seemed more intuitive to me, and I've wanted to do this more than once. Here's a toy example: for x in sequence: if x == "spam": print("exiting early") break elif x == "ham": print("exiting early") break do_something(x) would become: for x in sequence: if x == "spam": break elif x == "ham": break do_something(x) else: print("exiting early") > I think the choice of keyword is probably not Guido's crowning language > achievement, but then since the English keywords don't make natural > sense to those who speak other languages it's at least fair that there > should be one that isn't totally natural to English speakers. A small > price to pay for all the other keywords not being Dutch. Indeed :) -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Thu, 16 Dec 2010 21:49:07 +, John Gordon wrote: > (This is mostly a style question, and perhaps one that has already been > discussed elsewhere. If so, a pointer to that discussion will be > appreciated!) > > When I started learning Python, I wrote a lot of methods that looked > like this: > > > def myMethod(self, arg1, arg2): > > if some_good_condition: > > if some_other_good_condition: > > if yet_another_good_condition: > > do_some_useful_stuff() > exitCode = good1 > > else: > exitCode = bad3 > > else: > exitCode = bad2 > > else: > exitCode = bad1 > > return exitCode > > Another way to look at this is as question of object-oriented style, as you are using a method in your example... Arguably, rather than branching your code based on the arguments being passed to your method, you can embody the required behaviour in subclasses of your class, and at runtime just use an object that "does the right thing". Of course, you end up writing the same branching in some factory object instead, but at least it isn't cluttering up your business logic any longer. Trying to write an OO-style program without using any if statements in the business logic can be an interesting exercise, albeit not a terribly realistic one. Apologies if your choice of a method for your example was entirely incidental to your question :) Kev -- http://mail.python.org/mailman/listinfo/python-list
RE: If/then style question
-Original Message- You have outlined what happens when cond1 and cond2 both evaluate to True -- what happens if, say, cond2 evaluates to False? - I reply And the light goes on! (And palm strikes forehead.) I was thinking that the error we were processing was raised by the do_some_useful_stuff() function. But the whole purpose of this thread was to evaluate error conditions that might have been set before we do useful stuff! Which, of course, was what the original poster was asking. My thanks again for your patience. RobR -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 2010-12-16, Steven D'Aprano wrote: > On Thu, 16 Dec 2010 21:49:07 +, John Gordon wrote: > >> (This is mostly a style question, and perhaps one that has already been >> discussed elsewhere. If so, a pointer to that discussion will be >> appreciated!) >> >> When I started learning Python, I wrote a lot of methods that looked >> like this: >> >> def myMethod(self, arg1, arg2): >> if some_good_condition: >> if some_other_good_condition: >> if yet_another_good_condition: >> do_some_useful_stuff() >> exitCode = good1 >> else: >> exitCode = bad3 >> else: >> exitCode = bad2 >> else: >> exitCode = bad1 >> return exitCode > > > It doesn't look like you were learning Python. It looks like you were > learning C with Python syntax :( Let's not blame C for bad program structure. No good C programmer would use that construct either. One choice in C would look like this: if (some_condition) return code1; if (other_condition) return code2; if (condition3) return code3; //do whatever work really needs to be done here. return successCode; Or, if there's cleanup that needs to be done, then you "raise a an exception": if (condition1) { ret = code1; goto errexit; } if (condition2) { ret = code2; goto errexit; } if (condition3) { ret = code3; goto errexit; } // do the normal bit of work errexit: //cleanup return ret; -- Grant Edwards grant.b.edwardsYow! Awright, which one of at you hid my PENIS ENVY? gmail.com -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 2010-12-16, Stefan Sonnenberg-Carstens wrote: > The advantage in latter case is fewer operations, because you can > skip the assignments, and it is more readable. > > The "one entry, one exit" is an advice. Not a law. > Your code is OK. > > As long as it works ;-) Even that last bit isn't that important. Give me code that's easy-to-read and doesn't work rather code that works and can't be read any day. -- Grant Edwards grant.b.edwardsYow! What's the MATTER at Sid? ... Is your BEVERAGE gmail.comunsatisfactory? -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
> I now remember this idiom as the "break else" construct: either the loop > breaks, or the "else:" suite is executed. A perfect description. Malcolm -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Tim Golden writes: > On 17/12/2010 15:53, Steve Holden wrote: > > [... snip example of for-else ...] > >> This construct appears to be unpopular in actual use, and when it comes >> up in classes and seminars there is always interesting debate as people >> discuss potential uses and realise there are useful applications. > > I use this not infrequently, and I like it when it seems to be an > elegant way to express the code path. But I still misremember from > time to time and assume that the "else" clause fires when the for > loop is empty. I use it from time to time, even though, like you, I used to always be unsure when the "else:" suite would be executed. I now remember this idiom as the "break else" construct: either the loop breaks, or the "else:" suite is executed. -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Steve Holden writes: > I think the choice of keyword is probably not Guido's crowning > language achievement, I remember the behaviour by considering a typical application: for thing in things: if shinyp(thing): break else: raise DullError, 'nothing shiny found' In this kind of search loop, `break' signifies a kind of successful completion: the `for' loop can be considered to be a test acting over an iterable, and `else' therefore denotes the action if the test fails. I don't know whether that's the official intuition, or even if there is an official intuition, but it works well enough for me. I'm quite fond of Python's extra `else' clauses in `for' and (particularly) `try'. -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 12/17/2010 11:13 AM, Tim Golden wrote: > On 17/12/2010 15:53, Steve Holden wrote: > > [... snip example of for-else ...] > >> This construct appears to be unpopular in actual use, and when it comes >> up in classes and seminars there is always interesting debate as people >> discuss potential uses and realise there are useful applications. > > I use this not infrequently, and I like it when it seems to be an > elegant way to express the code path. But I still misremember from > time to time and assume that the "else" clause fires when the for > loop is empty. > Yes, that's a common misconception. The classical use is something like for item in possibilities: if item == target: break else: raise NotFound("Didn't find it") Though of course arguably that logic might be expressed in other ways, such as if target not in possibilities: raise NotFound("Didn't find it") regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Rob Richardson wrote: My thanks for pointing out the existence of the else: suite in the for statement. However, I remain confused. For reference, here's the original code: def myMethod(): for condition, exitCode in [ (cond1, 'error1'), (cond2, 'very bad error'), ]: if not condition: break else: do_some_usefull_stuff() # executed only if the we never hit the break statement. exitCode = good1 return exitCode What do we know about cond1 and cond2? Do they have to be assigned before this for statement is executed? The sample code doesn't show it. cond1 and cond2 should be expressions of some sort, e.g. check_files() or feedback (feedback being a variable of some sort). The loop is going to to execute once for condition = cond1 and exitCode = 'error1'. The only thing it's going to do is check to see what condition is. Since we can assume (I hope) that cond1 is not false, then the for loop continues. Now condition = cond2 and exitCode = 'very bad error'. The if condition is still false, so the loop continues. We've come to the end now, and the else: suite is executed. We finally do some useful stuff and exitCode = good1. (Should that have been in quotes, or doesn't it matter?) But now the for loop's job is done and we return the exitCode, which at this point is good1. But I still don't understand what happens if we can't do useful stuff. Where does an error code get set, and where is that error code checked? We don't have a chance to check it in the for loop, because once we're in the else: suite the loop condition is never rechecked. Or is it? You have outlined what happens when cond1 and cond2 both evaluate to True -- what happens if, say, cond2 evaluates to False? . . . . . if not cond2 becomes True, we hit the break, do not do do_some_usefull_stuff(), but proceed to return exitCode -- and exitCode was set in the for loop to 'very bad error' when condition was set to cond2. The exitCode no longer needs to be checked inside the function, because there is no chance of do_some_useful_stuff running if any of the conditions are False. Hope this helps. ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Jean-Michel Pichavant writes: > What about, > > def myMethod(): >for condition, exitCode in [ >(cond1, 'error1'), >(cond2, 'very bad error'), >]: >if not condition: >break >else: > do_some_usefull_stuff() # executed only if the we never hit the > break statement. > exitCode = good1 > >return exitCode > > This version uses the 'for ... else' statement. For..else always has seemed ugly and confusing to me, as does that thing of using the captured loop indexes after the loop finishes. I'd prefer a more functional style (untested): def myMethod(): def success(): do_some_usefull_stuff() return good1 cond_table = [ (cond1, lambda: 'error1'), (cond2, lambda: 'very bad error'), (True, success) ] func = next(f for c,f in cond_table if c) return func() This uses the next() builtin from Python 2.6. You could make it more concise: def myMethod(): cond_table = [ (cond1, lambda: 'error1'), (cond2, lambda: 'very bad error'), (True, lambda: (do_some_usefull_stuff(), good1)[1]) ] return next(f for c,f in cond_table if c)() -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 17/12/2010 15:53, Steve Holden wrote: [... snip example of for-else ...] This construct appears to be unpopular in actual use, and when it comes up in classes and seminars there is always interesting debate as people discuss potential uses and realise there are useful applications. I use this not infrequently, and I like it when it seems to be an elegant way to express the code path. But I still misremember from time to time and assume that the "else" clause fires when the for loop is empty. TJG -- http://mail.python.org/mailman/listinfo/python-list
RE: If/then style question
My thanks for pointing out the existence of the else: suite in the for statement. However, I remain confused. For reference, here's the original code: > def myMethod(): > for condition, exitCode in [ > (cond1, 'error1'), > (cond2, 'very bad error'), > ]: > if not condition: > break > else: >do_some_usefull_stuff() # executed only if the we never hit the > break statement. >exitCode = good1 > > return exitCode What do we know about cond1 and cond2? Do they have to be assigned before this for statement is executed? The sample code doesn't show it. The loop is going to to execute once for condition = cond1 and exitCode = 'error1'. The only thing it's going to do is check to see what condition is. Since we can assume (I hope) that cond1 is not false, then the for loop continues. Now condition = cond2 and exitCode = 'very bad error'. The if condition is still false, so the loop continues. We've come to the end now, and the else: suite is executed. We finally do some useful stuff and exitCode = good1. (Should that have been in quotes, or doesn't it matter?) But now the for loop's job is done and we return the exitCode, which at this point is good1. But I still don't understand what happens if we can't do useful stuff. Where does an error code get set, and where is that error code checked? We don't have a chance to check it in the for loop, because once we're in the else: suite the loop condition is never rechecked. Or is it? Thanks again! RobR -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 12/17/2010 9:38 AM, Steven D'Aprano wrote: > On Fri, 17 Dec 2010 09:09:49 -0500, Rob Richardson wrote: > > >> First, just to clarify, I don't think the indentation I saw was what was >> originally posted. The "else" must be indented to match the "if", and >> the two statements under "else" are in the else block. The return >> statement is indented at the same level as the for statement, so that it >> will be executed after the for loop exits. Correct? > > I think that what you are missing is that for-loops can include an else > clause too, like this: > > for x in (1,2,3): > ... print(x) > ... else: > ... print("finished") > ... > 1 > 2 > 3 > finished > > > The else block runs after the for block, unless you exit the entire block > by returning, raising an exception, or using break: > > for x in (1,2,3): > ... print(x) > ... if x == 3: break > ... else: > ... print("finished") > ... > 1 > 2 > 3 > > > Does that clear up what is going on? > > This construct appears to be unpopular in actual use, and when it comes up in classes and seminars there is always interesting debate as people discuss potential uses and realise there are useful applications. I think the choice of keyword is probably not Guido's crowning language achievement, but then since the English keywords don't make natural sense to those who speak other languages it's at least fair that there should be one that isn't totally natural to English speakers. A small price to pay for all the other keywords not being Dutch. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Thu, Dec 16, 2010 at 6:51 PM, Steven D'Aprano wrote: ... > Functions always have one entry. The only way to have multiple entry > points is if the language allows you to GOTO into the middle of a > function, and Python sensibly does not allow this. The "one entry, one > exit" rule comes from the days when people would routinely write > spaghetti code, jumping into and out of blocks of code without using > functions at all. Only 99.7% true. Fortran still allows the appalling ENTRY statement. -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Rob Richardson wrote: -Original Message- What about, def myMethod(): for condition, exitCode in [ (cond1, 'error1'), (cond2, 'very bad error'), ]: if not condition: break else: do_some_usefull_stuff() # executed only if the we never hit the break statement. exitCode = good1 return exitCode I reply - This is interesting, but I don't understand it (which speaks volumes about the level of my understanding of Python). First, just to clarify, I don't think the indentation I saw was what was originally posted. The "else" must be indented to match the "if", and the two statements under "else" are in the else block. No, the else is indented to the for loop. for ... else is a python statement, the else block is executed only if the loop did never break. http://docs.python.org/reference/compound_stmts.html#for The return statement is indented at the same level as the for statement, so that it will be executed after the for loop exits. Correct? Now, the for loop will set condition to cond1 and exitCode to 'error1'. Then it checks the contents of the condition variable. But what does "not " by itself mean? condition is a bool value. if not condition is evaluated to True, if the condition is False. condition = False not condition => True condition = ('Foo' == 'Foo') not condition => False [snip] RobR My mail client could have messed up with the indentation. Here is the code: http://paste-it.net/public/t8a4acd/python/ JM -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Fri, 17 Dec 2010 09:09:49 -0500, Rob Richardson wrote: > First, just to clarify, I don't think the indentation I saw was what was > originally posted. The "else" must be indented to match the "if", and > the two statements under "else" are in the else block. The return > statement is indented at the same level as the for statement, so that it > will be executed after the for loop exits. Correct? I think that what you are missing is that for-loops can include an else clause too, like this: >>> for x in (1,2,3): ... print(x) ... else: ... print("finished") ... 1 2 3 finished >>> The else block runs after the for block, unless you exit the entire block by returning, raising an exception, or using break: >>> for x in (1,2,3): ... print(x) ... if x == 3: break ... else: ... print("finished") ... 1 2 3 >>> Does that clear up what is going on? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
RE: If/then style question
-Original Message- What about, def myMethod(): for condition, exitCode in [ (cond1, 'error1'), (cond2, 'very bad error'), ]: if not condition: break else: do_some_usefull_stuff() # executed only if the we never hit the break statement. exitCode = good1 return exitCode I reply - This is interesting, but I don't understand it (which speaks volumes about the level of my understanding of Python). First, just to clarify, I don't think the indentation I saw was what was originally posted. The "else" must be indented to match the "if", and the two statements under "else" are in the else block. The return statement is indented at the same level as the for statement, so that it will be executed after the for loop exits. Correct? Now, the for loop will set condition to cond1 and exitCode to 'error1'. Then it checks the contents of the condition variable. But what does "not " by itself mean? I'm guessing that it checks that the variable refers to an object. So, the first time through, condition refers to cond1, the if condition is false, and the else block gets executed, and exitCode is changed to refer to good1. The next time through the loop, condition is set to refer to cond2 and exitCode is set to refer to 'very bad error'. Again, condition is refering to something, so the else block is executed and we do useful stuff again, which is probably not helpful and could well be harmful. exitCode is set to good1, we're finished with the loop, and we return exitCode. What happens if we try to do useful stuff, and we can't? Where does the error indication get set? And once it does get set, the only way we can exit the for loop is for condition to not refer to anything. How can that happen? Thank you very much for your explanation and your patience with one who only uses Python in very simplistic ways. RobR -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
John Gordon wrote: (This is mostly a style question, and perhaps one that has already been discussed elsewhere. If so, a pointer to that discussion will be appreciated!) When I started learning Python, I wrote a lot of methods that looked like this: def myMethod(self, arg1, arg2): if some_good_condition: if some_other_good_condition: if yet_another_good_condition: do_some_useful_stuff() exitCode = good1 else: exitCode = bad3 else: exitCode = bad2 else: exitCode = bad1 return exitCode But lately I've been preferring this style: def myMethod(self, arg1, arg2): if some_bad_condition: return bad1 elif some_other_bad_condition: return bad2 elif yet_another_bad_condition: return bad3 do_some_useful_stuff() return good1 I like this style more, mostly because it eliminates a lot of indentation. However I recall one of my college CS courses stating that "one entry, one exit" was a good way to write code, and this style has lots of exits. Are there any concrete advantages of one style over the other? Thanks. What about, def myMethod(): for condition, exitCode in [ (cond1, 'error1'), (cond2, 'very bad error'), ]: if not condition: break else: do_some_usefull_stuff() # executed only if the we never hit the break statement. exitCode = good1 return exitCode This version uses the 'for ... else' statement. You can easily add conditions by simply adding a line in the list, that's it. Note that this code uses a shadow declaration of exitCode in the for loop. If you're not comfortable with that, you'll have to use a properly 'declared' variable retCode and write retCode = exitCode before breaking. Actually I would advise to do so. JM -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Thu, 16 Dec 2010 20:32:29 -0800, Carl Banks wrote: > Even without the cleanup issue, sometimes you want to edit a function to > affect all return values somehow. If you have a single exit point you > just make the change there; if you have mulitple you have to hunt them > down and change all of them--if you remember to. I just got bit by that > one. If your function has so many exit points that you can miss some of them while editing, your function is too big, does too much, or both. Refactor and simplify. Or wrap the function in a decorator: def affect_all_return_values(func): @functools.wraps(func) def inner(*args, **kwargs): result = func(*args, **kwargs) do_something_to(result) return result return inner @affect_all_return_values def my_big_complicated_function(args): do_something_with_many_exit_points() -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 12/16/2010 11:32 PM, Carl Banks wrote: > On Dec 16, 2:56 pm, Ryan Kelly wrote: >> On Thu, 2010-12-16 at 21:49 +, John Gordon wrote: >>> (This is mostly a style question, and perhaps one that has already been >>> discussed elsewhere. If so, a pointer to that discussion will be >>> appreciated!) >> >>> When I started learning Python, I wrote a lot of methods that looked like >>> this: >> >>> def myMethod(self, arg1, arg2): >>> if some_good_condition: >>> if some_other_good_condition: >>> if yet_another_good_condition: >>> do_some_useful_stuff() >>> exitCode = good1 >>> else: >>> exitCode = bad3 >>> else: >>> exitCode = bad2 >>> else: >>> exitCode = bad1 >>> return exitCode >> >>> But lately I've been preferring this style: >> >>> def myMethod(self, arg1, arg2): >>> if some_bad_condition: >>> return bad1 >>> elif some_other_bad_condition: >>> return bad2 >>> elif yet_another_bad_condition: >>> return bad3 >>> do_some_useful_stuff() >>> return good1 >> >>> I like this style more, mostly because it eliminates a lot of indentation. >> >>> However I recall one of my college CS courses stating that "one entry, >>> one exit" was a good way to write code, and this style has lots of exits. >> >>> Are there any concrete advantages of one style over the other? >> >> "one entry, one exit" has its good points, but it's *way* overquoted and >> overused. >> >> Do you raise any exceptions? Do you call any functions that might raise >> exceptions? If so, you've got multiple exit points already. >> >> I think this style a lot more important in a language like C where you >> have to be super-careful about cleaning up after yourself. The single >> exit point makes it easier to verify that all cleanup tasks have been >> performed. Assuming you're using "with" or "try-finally" then you just >> don't need such guarantees in python. > > Even without the cleanup issue, sometimes you want to edit a function > to affect all return values somehow. If you have a single exit point > you just make the change there; if you have mulitple you have to hunt > them down and change all of them--if you remember to. I just got bit > by that one. > > It's a trade-off. Readability and/or conciseness versus error > robustness. I tend to go for the former but mileage varies. > Heaven forfend you should just wrap the existing function inside another one which takes its name, if all its returns need to be altered. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Dec 16, 2:56 pm, Ryan Kelly wrote: > On Thu, 2010-12-16 at 21:49 +, John Gordon wrote: > > (This is mostly a style question, and perhaps one that has already been > > discussed elsewhere. If so, a pointer to that discussion will be > > appreciated!) > > > When I started learning Python, I wrote a lot of methods that looked like > > this: > > > def myMethod(self, arg1, arg2): > > if some_good_condition: > > if some_other_good_condition: > > if yet_another_good_condition: > > do_some_useful_stuff() > > exitCode = good1 > > else: > > exitCode = bad3 > > else: > > exitCode = bad2 > > else: > > exitCode = bad1 > > return exitCode > > > But lately I've been preferring this style: > > > def myMethod(self, arg1, arg2): > > if some_bad_condition: > > return bad1 > > elif some_other_bad_condition: > > return bad2 > > elif yet_another_bad_condition: > > return bad3 > > do_some_useful_stuff() > > return good1 > > > I like this style more, mostly because it eliminates a lot of indentation. > > > However I recall one of my college CS courses stating that "one entry, > > one exit" was a good way to write code, and this style has lots of exits. > > > Are there any concrete advantages of one style over the other? > > "one entry, one exit" has its good points, but it's *way* overquoted and > overused. > > Do you raise any exceptions? Do you call any functions that might raise > exceptions? If so, you've got multiple exit points already. > > I think this style a lot more important in a language like C where you > have to be super-careful about cleaning up after yourself. The single > exit point makes it easier to verify that all cleanup tasks have been > performed. Assuming you're using "with" or "try-finally" then you just > don't need such guarantees in python. Even without the cleanup issue, sometimes you want to edit a function to affect all return values somehow. If you have a single exit point you just make the change there; if you have mulitple you have to hunt them down and change all of them--if you remember to. I just got bit by that one. It's a trade-off. Readability and/or conciseness versus error robustness. I tend to go for the former but mileage varies. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
"Steven D'Aprano" wrote in message news:4d0aa5e7$0$29997$c3e8da3$54964...@news.astraweb.com... It doesn't look like you were learning Python. It looks like you were learning C with Python syntax :( True, although in many cases one has to interface to legacy C code where it'd be rather more code to start throwing exceptions left or right... since sooner or later those exceptions would still have to be turned into a single status (error) code! which all too often becomes: result = obj.myMethod(arg1, arg2) if result == good1: do_something_good() else: # assume result is bad1 handle_error1() This really isn't a bad way to go *if you weren't planning on spending the time to really, fully flesh out the individual error cases anyway.* I see this pretty often: Peple put in sophisticated exception handling infrastructure, but when an error actually occurs, all six dozen cases handled individually end up just printing some generic message and exiting the program anyway. In an ideal world all the error cases would do something "smart," but pragmatically one has to balance how likely an error is to occur and how much damage it does with how much time you want to spend making a really smart error handler. or even: who_cares = obj.myMethod(arg1, arg2) do_something_good() Even this can be OK if do_something_good() behaves in a relatively benign fashion when feed gibberish. I mean, how many people actually check to see whether or not printf() succeeded, you know? But I would agree that often you see... who_care = obj.myMethod(arg1, arg2) do_something_really_dangerous_that_depends_on_the_success_of_myMethod() :-) Well, that's better, but still more like C rather than Python. Avoid the anti-pattern of returning in-band error codes. The main sticky point here is that what's an "error" vs. a "warning" or "note" (but not "success") is often rather a grey area. E.g., Pyhton's open() raises an IOError is the file can't be opened, but in my mind that's still a common enough/expected occurrence that elevating its behavior to an exception is more a judgement call than something everyone would agree on. (On the other hand, trying to read or write to an un-opened file is now clearly in the realm of an error and deserves an exception.) ---Joel -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
John Gordon wrote: > But lately I've been preferring this style: > > def myMethod(self, arg1, arg2): > > if some_bad_condition: > return bad1 > > elif some_other_bad_condition: > return bad2 > > elif yet_another_bad_condition: > return bad3 > > do_some_useful_stuff() > return good1 For more than 2 tests in a function like this, I'd probably use dictionary dispatch: def myMethod(self, arg1, arg2): branches = dict( cond1: bad1, cond2: bad2, cond3: bad3 ) cond = if cond == cond_good: do_some_useful_stuff() exitCode = good1 else: exitCode = branches[cond] return exitCode -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Thu, 16 Dec 2010 21:49:07 +, John Gordon wrote: > (This is mostly a style question, and perhaps one that has already been > discussed elsewhere. If so, a pointer to that discussion will be > appreciated!) > > When I started learning Python, I wrote a lot of methods that looked > like this: > > def myMethod(self, arg1, arg2): > if some_good_condition: > if some_other_good_condition: > if yet_another_good_condition: > do_some_useful_stuff() > exitCode = good1 > else: > exitCode = bad3 > else: > exitCode = bad2 > else: > exitCode = bad1 > return exitCode It doesn't look like you were learning Python. It looks like you were learning C with Python syntax :( The above would be more Pythonically written as: def myMethod(self, arg1, arg2): if not some_good_condition: raise SomeException("message") if not some_other_good_condition: raise SomeOtherException("another message") if yet_another_good_condition: do_some_useful_stuff() else: raise SomeThirdException("whatever") using exceptions to communicate errors out-of-band. Since no return result is needed, no explicit return is used and the method is the closest thing to a procedure that Python can offer. The problem with in-band transmission of errors is that they invite the anti-pattern of this: result = obj.myMethod(arg1, arg2) if result == good1: do_something_good() elif result == bad1: handle_error1() elif result == bad2: handle_error2() elif result == bad3(): handle_error3() else: print "This can't ever happen, but if it does..." which all too often becomes: result = obj.myMethod(arg1, arg2) if result == good1: do_something_good() else: # assume result is bad1 handle_error1() or even: who_cares = obj.myMethod(arg1, arg2) do_something_good() > But lately I've been preferring this style: > > def myMethod(self, arg1, arg2): > if some_bad_condition: > return bad1 > elif some_other_bad_condition: > return bad2 > elif yet_another_bad_condition: > return bad3 > do_some_useful_stuff() > return good1 > > I like this style more, mostly because it eliminates a lot of > indentation. Well, that's better, but still more like C rather than Python. Avoid the anti-pattern of returning in-band error codes. In some languages, either exceptions aren't available at all, or the overhead of them is so great that for performance you have to avoid them, but Python is not one of those languages. In Python, exceptions are *the* primary way of communicating exceptional cases such as (but not limited to) errors. I can only think of two, er, exceptions to this rule: str.find() and some of the regular expression methods. > However I recall one of my college CS courses stating that "one entry, > one exit" was a good way to write code, and this style has lots of > exits. Functions always have one entry. The only way to have multiple entry points is if the language allows you to GOTO into the middle of a function, and Python sensibly does not allow this. The "one entry, one exit" rule comes from the days when people would routinely write spaghetti code, jumping into and out of blocks of code without using functions at all. If "one entry" is pointless (all functions have one entry!) then "one exit" is actively harmful. It leads to adding unnecessary complexity to functions, purely to meet the requirements of a rule invented to discourage spaghetti code. This hides bugs and increases the maintenance burden. Don't get me wrong... spaghetti code is *bad*. But there are other ways of writing bad code too, and hanging around inside a function long after you've finished is also bad: def function(arg): done = False do_something() if some_condition: result = "finished" done = True if not done: do_something_else() if another_condition: result = "now we're finished" done = True if not done: do_yet_more_work() if third_condition: result = "finished this time for sure" done = True if not done: for i in range(100): if not done: do_something_small() if yet_another_condition: result = "finally done!" done = True return result It's far more complicated than it need be, and does *lots* of unnecessary work. This can be written more simply and efficiently as: def function(arg): do_something() if some_condition: return "finished" do_something_else() if another_condition: return "now we're finished" do_yet_more_work() if third_condition: return "finished this time for sure" for i in range(100): do_something_small() if yet_another_condition: return "fin
Re: If/then style question
On Thu, Dec 16, 2010 at 3:41 PM, Stefan Sonnenberg-Carstens wrote: > return [x for x,y in > ((bad1,some_bad_condition),(bad2,some_other_bad_condition),(bad3,yet_another_bad_condition),(good1,do_some_useful_stuff() > or True)) if x][0] This doesn't work. do_some_usefull_stuff() gets called during the tuple construction regardless of the conditions, not during the list comprehension execution as you would want. Here's my take on an unreadable one-liner: return reduce(lambda x, y: (x or (y[0]() and y[1])), [(some_bad_condition, bad1), (some_other_bad_condition, bad2), (yet_another_bad_condition, bad3), (lambda: (do_some_useful_stuff() or True), good1)], None) This of course assumes that bad1, bad2, and bad3 all evaluate as true. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On Thu, 2010-12-16 at 21:49 +, John Gordon wrote: > (This is mostly a style question, and perhaps one that has already been > discussed elsewhere. If so, a pointer to that discussion will be > appreciated!) > > When I started learning Python, I wrote a lot of methods that looked like > this: > > > def myMethod(self, arg1, arg2): > if some_good_condition: > if some_other_good_condition: > if yet_another_good_condition: > do_some_useful_stuff() > exitCode = good1 > else: > exitCode = bad3 > else: > exitCode = bad2 > else: > exitCode = bad1 > return exitCode > > > But lately I've been preferring this style: > > > def myMethod(self, arg1, arg2): > if some_bad_condition: > return bad1 > elif some_other_bad_condition: > return bad2 > elif yet_another_bad_condition: > return bad3 > do_some_useful_stuff() > return good1 > > I like this style more, mostly because it eliminates a lot of indentation. > > However I recall one of my college CS courses stating that "one entry, > one exit" was a good way to write code, and this style has lots of exits. > > Are there any concrete advantages of one style over the other? "one entry, one exit" has its good points, but it's *way* overquoted and overused. Do you raise any exceptions? Do you call any functions that might raise exceptions? If so, you've got multiple exit points already. I think this style a lot more important in a language like C where you have to be super-careful about cleaning up after yourself. The single exit point makes it easier to verify that all cleanup tasks have been performed. Assuming you're using "with" or "try-finally" then you just don't need such guarantees in python. I'm not a PEP-8 pedant by any means, but I think that the first section of PEP-8 contains the best advice I've ever read about programming language style. In fact, I'm going to quote it right here: A Foolish Consistency is the Hobgoblin of Little Minds == One of Guido's key insights is that code is read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Python code. As PEP 20 says, "Readability counts". ...snip... But most importantly: know when to be inconsistent -- sometimes the style guide just doesn't apply. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don't hesitate to ask! In your example, the first style is difficult to read wile the second style is easy to read. You don't need any further justification for preferring the latter. Cheers, Ryan -- Ryan Kelly http://www.rfk.id.au | This message is digitally signed. Please visit r...@rfk.id.au| http://www.rfk.id.au/ramblings/gpg/ for details signature.asc Description: This is a digitally signed message part -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
Am 16.12.2010 22:49, schrieb John Gordon: (This is mostly a style question, and perhaps one that has already been discussed elsewhere. If so, a pointer to that discussion will be appreciated!) When I started learning Python, I wrote a lot of methods that looked like this: def myMethod(self, arg1, arg2): if some_good_condition: if some_other_good_condition: if yet_another_good_condition: do_some_useful_stuff() exitCode = good1 else: exitCode = bad3 else: exitCode = bad2 else: exitCode = bad1 return exitCode But lately I've been preferring this style: def myMethod(self, arg1, arg2): if some_bad_condition: return bad1 elif some_other_bad_condition: return bad2 elif yet_another_bad_condition: return bad3 else: do_some_useful_stuff() return good1 I like this style more, mostly because it eliminates a lot of indentation. However I recall one of my college CS courses stating that "one entry, one exit" was a good way to write code, and this style has lots of exits. Are there any concrete advantages of one style over the other? Thanks. The advantage in latter case is fewer operations, because you can skip the assignments, and it is more readable. The "one entry, one exit" is an advice. Not a law. Your code is OK. As long as it works ;-) P.S.: Sorry, I could not resist: return bad1 if some_bad_condition else bad2 if some_other_bad_condition else bad3 if yet_another_bad_condition else good1 if do_some_useful_stuff() else good1 Or consider this: return [x for x,y in ((bad1,some_bad_condition),(bad2,some_other_bad_condition),(bad3,yet_another_bad_condition),(good1,do_some_useful_stuff() or True)) if x][0] Neither self explanatory nor readable :-( -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 2010-12-16, John Gordon wrote: > (This is mostly a style question, and perhaps one that has already been > discussed elsewhere. If so, a pointer to that discussion will be > appreciated!) > > When I started learning Python, I wrote a lot of methods that looked like > this: > > > def myMethod(self, arg1, arg2): > if some_good_condition: > if some_other_good_condition: > if yet_another_good_condition: > do_some_useful_stuff() > exitCode = good1 > else: > exitCode = bad3 > else: > exitCode = bad2 > else: > exitCode = bad1 > return exitCode > > > But lately I've been preferring this style: > > > def myMethod(self, arg1, arg2): > > if some_bad_condition: > return bad1 > > elif some_other_bad_condition: > return bad2 > > elif yet_another_bad_condition: > return bad3 > > do_some_useful_stuff() > return good1 > > I like this style more, mostly because it eliminates a lot of > indentation. There's nothing inherently wrong with indentation, but in this case the latter style is a _lot_ easier to read (and modify without breaking). > However I recall one of my college CS courses stating that "one > entry, one exit" was a good way to write code, and this style has > lots of exits. > > Are there any concrete advantages of one style over the other? I think the check/exit style is far more readable. It can trip you up if there is cleanup stuff that needs to happen before you return from the function. In that case putting the whole function in a try statement and raising exceptions for the "bad conditions" works nicely. Then you get the more readable style of the check/exit style, plus the advantage of a single exit (it's easy to verify visually that all the required cleanup is happening). -- Grant Edwards grant.b.edwardsYow! I want a WESSON OIL at lease!! gmail.com -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
On 2010-12-16, John Gordon wrote: > I like this style more, mostly because it eliminates a lot of indentation. > > However I recall one of my college CS courses stating that "one entry, > one exit" was a good way to write code, and this style has lots of exits. So, take the good intentation from one and the single exit from the other: def myMethod(self, arg1, arg2): if some_bad_condition: exitCode = bad1 elif some_other_bad_condition: exitCode = bad2 elif yet_another_bad_condition: exitCode = bad3 else: exitCode = do_some_useful_stuff() # possible common cleanup code here return exitCode Or, raise an exception on bad condtions rather then passing an error code. -- http://mail.python.org/mailman/listinfo/python-list
Re: If/then style question
John Gordon wrote: (This is mostly a style question, and perhaps one that has already been discussed elsewhere. If so, a pointer to that discussion will be appreciated!) When I started learning Python, I wrote a lot of methods that looked like this: def myMethod(self, arg1, arg2): if some_good_condition: if some_other_good_condition: if yet_another_good_condition: do_some_useful_stuff() exitCode = good1 else: exitCode = bad3 else: exitCode = bad2 else: exitCode = bad1 return exitCode But lately I've been preferring this style: def myMethod(self, arg1, arg2): if some_bad_condition: return bad1 elif some_other_bad_condition: return bad2 elif yet_another_bad_condition: return bad3 do_some_useful_stuff() return good1 I like this style more, mostly because it eliminates a lot of indentation. As far as if/else goes, I prefer the second style also. As far as returning bad codes, you are better off raising exceptions: def myMethod(self, arg1, arg2): if some_bad_condition: raise Bad1() elif some_other_bad_condition: raise Bad2() elif yet_another_bad_condition: raise Bad3() do_some_useful_stuff # no need to return 'good' code -- success means no problems ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list