Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #62541 > unrolled thread

cascading python executions only if return code is 0

Started byFrank Cui <ycui@outlook.com>
First post2013-12-22 15:37 -0300
Last post2013-12-23 15:22 +0000
Articles 20 on this page of 67 — 18 participants

Back to article view | Back to comp.lang.python


Contents

  cascading python executions only if return code is 0 Frank Cui <ycui@outlook.com> - 2013-12-22 15:37 -0300
    Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-22 14:17 -0500
      Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-22 19:31 +0000
        Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-22 15:05 -0500
          Re: cascading python executions only if return code is 0 Cameron Simpson <cs@zip.com.au> - 2013-12-23 08:39 +1100
            Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-22 16:53 -0500
              Re: cascading python executions only if return code is 0 Cameron Simpson <cs@zip.com.au> - 2013-12-23 09:11 +1100
              Re: cascading python executions only if return code is 0 Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-12-22 22:10 -0500
              Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 14:22 +1100
              Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-23 03:43 +0000
              Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 14:45 +1100
              Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-23 03:54 +0000
              Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 14:59 +1100
      RE: cascading python executions only if return code is 0 Frank Cui <ycui@outlook.com> - 2013-12-22 16:10 -0300
      Re: cascading python executions only if return code is 0 Ned Batchelder <ned@nedbatchelder.com> - 2013-12-22 14:49 -0500
        Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-23 00:08 +0000
      RE: cascading python executions only if return code is 0 Frank Cui <ycui@outlook.com> - 2013-12-22 16:35 -0300
        Re: cascading python executions only if return code is 0 Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-12-23 13:30 +1300
    Re: cascading python executions only if return code is 0 Rick Johnson <rantingrickjohnson@gmail.com> - 2013-12-22 14:27 -0800
      RE: cascading python executions only if return code is 0 Frank Cui <ycui@outlook.com> - 2013-12-22 19:14 -0300
      Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 09:51 +1100
      Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-22 23:02 +0000
        Re: cascading python executions only if return code is 0 Rick Johnson <rantingrickjohnson@gmail.com> - 2013-12-22 15:57 -0800
          Re: cascading python executions only if return code is 0 Ned Batchelder <ned@nedbatchelder.com> - 2013-12-23 07:27 -0500
          Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-23 12:44 +0000
    Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-23 00:25 +0000
      Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-22 20:24 -0500
        Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 12:35 +1100
        Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-23 13:33 +1100
          Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 14:09 +1100
          Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-22 23:57 -0500
            Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-23 16:09 +1100
            Re: cascading python executions only if return code is 0 Ethan Furman <ethan@stoneleaf.us> - 2013-12-23 04:45 -0800
              Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-23 10:10 -0500
                Re: cascading python executions only if return code is 0 Ethan Furman <ethan@stoneleaf.us> - 2013-12-23 08:00 -0800
                  Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-26 20:37 -0500
                    Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-27 12:44 +1100
                    Re: cascading python executions only if return code is 0 Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-12-26 21:20 -0500
                    Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-27 13:27 +1100
                      Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-26 23:29 -0500
                        Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-27 15:40 +1100
                        Re: cascading python executions only if return code is 0 Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-12-27 11:15 -0500
                          Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-27 11:42 -0500
                            Re: cascading python executions only if return code is 0 Rustom Mody <rustompmody@gmail.com> - 2013-12-27 22:39 +0530
                            Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-28 08:24 +1100
                            Re: cascading python executions only if return code is 0 pecore@pascolo.net - 2013-12-28 00:59 +0100
                              Re: cascading python executions only if return code is 0 Gene Heskett <gheskett@wdtv.com> - 2013-12-27 19:12 -0500
                    Re: cascading python executions only if return code is 0 Tim Chase <python.list@tim.thechases.com> - 2013-12-26 20:50 -0600
                    Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-27 15:39 +1100
                      Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-27 15:45 +1100
                      Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-27 00:05 -0500
                        Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-27 16:15 +1100
                          Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-27 00:41 -0500
                    Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-27 18:00 +0000
                    Re: cascading python executions only if return code is 0 Grant Edwards <invalid@invalid.invalid> - 2013-12-30 17:36 +0000
                Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-24 04:05 +1100
                  Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-23 11:03 -0800
                    Re: cascading python executions only if return code is 0 Chris Angelico <rosuav@gmail.com> - 2013-12-24 06:12 +1100
                    RE: cascading python executions only if return code is 0 Nick Cash <nick.cash@npcinternational.com> - 2013-12-23 19:31 +0000
                    Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-24 14:41 +1100
                      Re: cascading python executions only if return code is 0 Roy Smith <roy@panix.com> - 2013-12-23 22:58 -0500
                Re: cascading python executions only if return code is 0 Peter Otten <__peter__@web.de> - 2013-12-23 18:45 +0100
            Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-23 13:20 +0000
          Re: cascading python executions only if return code is 0 Ethan Furman <ethan@stoneleaf.us> - 2013-12-23 04:38 -0800
          Re: cascading python executions only if return code is 0 Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-12-23 10:12 -0500
            Re: cascading python executions only if return code is 0 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-12-24 04:13 +1100
          Re: cascading python executions only if return code is 0 Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-12-23 15:22 +0000

Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →


#62560

FromChris Angelico <rosuav@gmail.com>
Date2013-12-23 09:51 +1100
Message-ID<mailman.4515.1387752719.18130.python-list@python.org>
In reply to#62558
On Mon, Dec 23, 2013 at 9:14 AM, Frank Cui <ycui@outlook.com> wrote:
> Thanks for pointing out. I accept your advice and will try to make the
> questions clearer and more straightforward to interpretate . I already took
> the suggestion of using exception-based handling over the return code.
>
> As to testing whether the previous function fails or succeeds, this doesn't
> really matter in the sense that I already mentioned a return code of 0.

Ranting Rick is one of the list's resident trolls. Don't take it amiss
that he turned his flamethrowers on you. :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#62561

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2013-12-22 23:02 +0000
Message-ID<mailman.4516.1387753377.18130.python-list@python.org>
In reply to#62558
On 22/12/2013 22:51, Chris Angelico wrote:
> On Mon, Dec 23, 2013 at 9:14 AM, Frank Cui <ycui@outlook.com> wrote:
>> Thanks for pointing out. I accept your advice and will try to make the
>> questions clearer and more straightforward to interpretate . I already took
>> the suggestion of using exception-based handling over the return code.
>>
>> As to testing whether the previous function fails or succeeds, this doesn't
>> really matter in the sense that I already mentioned a return code of 0.
>
> Ranting Rick is one of the list's resident trolls. Don't take it amiss
> that he turned his flamethrowers on you. :)
>
> ChrisA
>

Given that Frank originally stated this

"
I have a requirement where I need to sequentially execute a bunch of 
executions, each execution has a return code. the followed executions 
should only be executed if the return code is 0. is there a cleaner or 
more pythonic way to do this other than the following ?

if a() == 0:
     if b() == 0:
         c()
"

I can only see one way that you can possibly intepret it.  Perhaps rr 
was dashing off a reply on a mobile device while doing a home run, hence 
wasn't concentrating on what Frank had actually said?

-- 
My fellow Pythonistas, ask not what our language can do for you, ask 
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#62618

FromRick Johnson <rantingrickjohnson@gmail.com>
Date2013-12-22 15:57 -0800
Message-ID<420afeb9-674f-4974-8f6d-6cc80c7f57b1@googlegroups.com>
In reply to#62561
On Sunday, December 22, 2013 5:02:51 PM UTC-6, Mark Lawrence wrote:
> On 22/12/2013 22:51, Chris Angelico wrote:

> if a() == 0:
>
>      if b() == 0:
>
>          c()
>
> I can only see one way that you can possibly intepret it.

Hmm, I guess i should not assume color vision to be ubiquitous.

> [snip]

The level of abstraction of that code sample is so high that
no one should assume anything from reading it. The only fact
we CAN be sure of is that IF a() equals 0 and b() equals 0
then c will execute. But that fact gives us no insight into
Frank's *real* source code, not to mention his mind.

Sure. We always want folks to trim example code to it's most
relevant parts before presenting the code on this list, but
just as ten thousands lines of code is useless, so too is 4
lines. It's not the number of lines that matter so much as
the context those line provide to the problem at hand.

If you take the small code example literally, then why does
Frank even need to ask a question about what will happen
when he could simply run the code and observe the results.

Here is the most simplified example of Franks code:

    if 0 == 0:
        if 0 == 0:
            do_something()

This code is so *confined* as to be useless for
generalities. In fact, the only reason to ask a question
about such simplified code is to understand the execution
rules OR syntax of Python source code. Here are some
concrete facts about those three lines:

    1. test one will ALWAYS eval true, and proceed to test two

    2. test two will ALWAYS eval true, then execute "do_something"

    3. what happens after that is undefined

These are fundamental behaviors of Python conditionals,
operators, callables, etc... which we *already* understand
quite completely. But these fundamentals will not help us
understand Frank's problem.

    What we need is help Frank is *CONTEXT*.

Now, even though Frank's code offers a small increment in
complexity over my simplified form, it offers *zero*
context of that complexity:

    1. test one will evaluate true or false, then proceed (or
    not, depending on the return value of "a") to test two

    2. test two will evaluate true or false, then proceed (or
    not, depending on the return value of "b") to execute the
    body

    3. What happens in a, b, and c is undefined.

The problem is we have no idea what happens in a,b,and c...
but those facts may not matter, what does matter is what a
return value of zero *means* to Frank, and without an
understanding of these "Frank semantics", how could we
possibly extrapolate a solution to such ambiguous questions?

You see, there exist no rules in Python for what a return
value of 0 should mean. Should it mean "success"? Should it
mean "failure"? Should it mean "eat pasta quickly"? Well it
could mean all those things to different people.

Since function return values are defined by programmers,
*ONLY* the programmer himself-- or those familiar with the
entire code base --can resolve the ambiguities with any
degree of precision.

Even IF you are presented with a small snippet of code that
include the identifier for the return value, you still
cannot be certain that extrapolating meaning from an
identifier *alone* will give you the insight to remove all
ambiguity.

For example, let's say the return value is "proceed" and
attached to name spelled "flag". Do you really think you can
extrapolate the purpose of that value being returned?

"proceed" with what?

    Proceed counting unicorns?
    Proceed raising exceptions?
    Proceed extrapolating to infinity and beyond?!

You can guess, but that is all. Which brings us full circle
to the problem at hand.

[toc] | [prev] | [next] | [standalone]


#62620

FromNed Batchelder <ned@nedbatchelder.com>
Date2013-12-23 07:27 -0500
Message-ID<mailman.4550.1387801661.18130.python-list@python.org>
In reply to#62618
On 12/22/13 6:57 PM, Rick Johnson wrote:
> Even IF you are presented with a small snippet of code that
> include the identifier for the return value, you still
> cannot be certain that extrapolating meaning from an
> identifier*alone*  will give you the insight to remove all
> ambiguity.
>
> For example, let's say the return value is "proceed" and
> attached to name spelled "flag". Do you really think you can
> extrapolate the purpose of that value being returned?
>
> "proceed" with what?
>
>      Proceed counting unicorns?
>      Proceed raising exceptions?
>      Proceed extrapolating to infinity and beyond?!
>
> You can guess, but that is all. Which brings us full circle
> to the problem at hand.

You seem to be arguing that the original question didn't have enough 
information to be usefully answered.  You are doing this after the OP 
got an answer he was pleased with.

Yes, the question had some ambiguity.  That's why other people engaged 
with him to get to a useful point.  Waxing philosophically about the 
impossibility of asking the question isn't helpful.

-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [prev] | [next] | [standalone]


#62621

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2013-12-23 12:44 +0000
Message-ID<mailman.4551.1387802656.18130.python-list@python.org>
In reply to#62618
On 22/12/2013 23:57, Rick Johnson wrote:
> On Sunday, December 22, 2013 5:02:51 PM UTC-6, Mark Lawrence wrote:
>> On 22/12/2013 22:51, Chris Angelico wrote:
>
>> if a() == 0:
>>
>>       if b() == 0:
>>
>>           c()
>>
>> I can only see one way that you can possibly intepret it.
>

[snip molehill turned into Himalayas]

Again Frank's original question.

"
I have a requirement where I need to sequentially execute a bunch of 
executions, each execution has a return code. the followed executions 
should only be executed if the return code is 0. is there a cleaner or 
more pythonic way to do this other than the following ?

if a() == 0:
     if b() == 0:
         c()
"

What is so difficult to understand about "is there a cleaner or more 
pythonic way to do this other than the following?"  Peter Otten for one 
certainly managed to get it, and as always managed to beat me to the draw :(

-- 
My fellow Pythonistas, ask not what our language can do for you, ask 
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#62566

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-12-23 00:25 +0000
Message-ID<52b782db$0$6599$c3e8da3$5496439d@news.astraweb.com>
In reply to#62541
On Sun, 22 Dec 2013 15:37:04 -0300, Frank Cui wrote:

> hey guys,
> I have a requirement where I need to sequentially execute a bunch of
> executions, each execution has a return code. the followed executions
> should only be executed if the return code is 0. is there a cleaner or
> more pythonic way to do this other than the following ? 
> if a() == 0:
>     if b() == 0:
>         c()

I don't believe there is a clean way to deal with error return codes in 
*any* language, but certainly not Python.

If you only have a few such functions, you can mis-use boolean operators 
to get the result you want, at the cost of misleading code:

a() == 0 and b() == 0 and c()

But that's pretty horrible code, because it looks like you're testing a 
condition when you're really trying to run a, b, c etc. for their side-
effects. Code that relies on side-effects is usually a sign of poor 
design.

A better alternative is to modify the functions so that instead of 
returning 0 on failure and (I'm guessing here) None on success, they 
raise an exception instead. Instead of:

def a():
    do_this()
    do_that()
    if condition:
        return 0
    do_something_else()


you re-write it as:

def a():
    do_this()
    do_that()
    if condition:
        raise SomeError("something broke")
    do_something_else()


Then you can do this:


try:
    a()
    b()
    c()
except SomeError:
    handle_error()


What if you can't edit all the various a, b, c functions because other 
parts of your code rely on them returning an error result? That's easy, 
you just need an adaptor:

import functools

def adapt(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        if result == 0:
            raise SomeError("some message")
    return inner


try:
    adapt(a)()
    adapt(b)()
    adapt(c)()
except SomeError:
    handle_error()


Another option really only applies if all the functions use the same set 
of arguments.

def chain(list_of_functions, *args, **kwargs):
    for func in list_of_functions:
        result = func(*args, **kwargs)
        if result == 0:
            break


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#62572

FromRoy Smith <roy@panix.com>
Date2013-12-22 20:24 -0500
Message-ID<roy-5F73A5.20241022122013@news.panix.com>
In reply to#62566
In article <52b782db$0$6599$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> Code that relies on side-effects is usually a sign of poor 
> design.

I don't understand what you're trying to say there.  A bit later in your 
post, you wrote:

try:
    a()
    b()
    c()
except SomeError:
    handle_error()

Clearly, since the return values of a(), b(), and c() aren't saved, the 
only reason they're getting called is for their side effects.  And I 
don't see anything wrong with that.

BTW, there's a pattern we use a bunch in the Songza server code, which 
is sort of this, but in reverse.  We'll have a bunch of possible ways to 
do something (strategies, to use the pattern vernacular), and want to 
try them all in order until we find one which works.  So, for example:

        classes = [ClientDebugPicker,
                   StatefulSongPicker,
                   SWS_SequentialSongPicker,
                   StandardSongPicker]
        for cls in classes:
            picker = cls.create(radio_session, station, artist)
            if picker:
                return picker
        else:
            assert 0, "can't create picker (classes = %s)" % classes

Each SongPicker subclass encapsulates some logic for how to pick the 
next song.  It can also decide if the strategy it implements is 
appropriate for the particular request; create() either returns an 
instance of the class, or None.  Returning None means, "I'm not the 
right picker for this request; try the next one and see what he says".

[toc] | [prev] | [next] | [standalone]


#62576

FromChris Angelico <rosuav@gmail.com>
Date2013-12-23 12:35 +1100
Message-ID<mailman.4520.1387762546.18130.python-list@python.org>
In reply to#62572
On Mon, Dec 23, 2013 at 12:24 PM, Roy Smith <roy@panix.com> wrote:
> Each SongPicker subclass encapsulates some logic for how to pick the
> next song.  It can also decide if the strategy it implements is
> appropriate for the particular request; create() either returns an
> instance of the class, or None.  Returning None means, "I'm not the
> right picker for this request; try the next one and see what he says".

But in that instance, the picker has done nothing. The main effect is
to return a value, and since it returned None, you go on to do
something else.

This looks fine:

foo = a() or b() or c()

And it also looks like it would be safe to drop one of the calls if
you know it won't succeed:

if no_way_that_b_will_work:
    foo = a() or c()

The point about side effects is that b() still has to be called, here,
and the original statement doesn't make that clear. When you call a
function and ignore its return value, you're clearly doing it for its
side effects. Imagine this:

width_required = max(len(foo),len(bar),len(quux))

Any sane reader is going to assume that the length checks aren't going
to have side effects... but they could! Imagine if testing the length
of something forced it to be loaded into memory, thus triggering any
exception that would otherwise not be triggered until the thing got
loaded much later. Vaguely plausible, but bad design because it's
extremely unclear.

ChrisA

[toc] | [prev] | [next] | [standalone]


#62577

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-12-23 13:33 +1100
Message-ID<52b7a0e4$0$29994$c3e8da3$5496439d@news.astraweb.com>
In reply to#62572
Roy Smith wrote:

> In article <52b782db$0$6599$c3e8da3$5496439d@news.astraweb.com>,
>  Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> 
>> Code that relies on side-effects is usually a sign of poor
>> design.
> 
> I don't understand what you're trying to say there.

I'm trying to say that code that relies on side-effects is usually a sign of
poor design. Is that more clear now? :-)

I'm not a functional programming zealot, but imperative programming that
relies on side-effects is often harder to reason about than functional
style, due to lack of locality in its effects. With functions that
communicate only through their input arguments and output result, you don't
have to look far to see the effects the function call has: it is *only* in
the return result. But if it has side-effects, you potentially have to
inspect the entire program and environment to see what it has done.

Now of course sometimes the whole point of the function is to have a
side-effect (print something, delete or save a file, start up the car's
engine, ...) and even functional languages usually have some facility for
side-effects. And we can often limit the harm of relying on side-effects
but narrowly constraining what those side-effects are.

E.g. list.append has a very narrow and well-defined side-effect, which makes
it relatively easy to reason about it. But still not as easy as perhaps we
would like:

alist = blist = [1, 2, 4, 8]
# later on
alist.append(16)  # operates by side-effect
# and still later on
assert blist == [1, 2, 4, 8]  # FAILS!!!


A side-effect free language might make list.append return a new list with
the extra value appended, and then the above would not occur. But I
digress.

The point is, I'm not saying that imperative code that operates via
side-effects is always harmful. There are degrees of badness.


> A bit later in your 
> post, you wrote:
> 
> try:
>     a()
>     b()
>     c()
> except SomeError:
>     handle_error()
> 
> Clearly, since the return values of a(), b(), and c() aren't saved, the
> only reason they're getting called is for their side effects.

That's not my design :-)


> And I don't see anything wrong with that.

And quite frankly, neither do I. But I don't know what a, b and c actually
do.


> BTW, there's a pattern we use a bunch in the Songza server code, which
> is sort of this, but in reverse.  We'll have a bunch of possible ways to
> do something (strategies, to use the pattern vernacular), and want to
> try them all in order until we find one which works.

Sounds reasonable. You're not operating by side-effect, since you actually
do want the result generated by the strategy. Presumably the strategy
signature is to return None on failure, or instance on success. (I see
below that's exactly what you do.)


> So, for example: 
> 
>         classes = [ClientDebugPicker,
>                    StatefulSongPicker,
>                    SWS_SequentialSongPicker,
>                    StandardSongPicker]
>         for cls in classes:
>             picker = cls.create(radio_session, station, artist)
>             if picker:
>                 return picker

This seems perfectly reasonable up. The strategy either returns a picker, in
which case you are done, or it returns None and you continue. No
side-effects are involved.


>         else:
>             assert 0, "can't create picker (classes = %s)" % classes

¡Ay, caramba! I was with you until the very last line. The above code is
possibly buggy and inappropriately designed. (I may be completely
misinterpreting this, in which case feel free to ignore the following
rant.)

First, the bug: there are circumstances where no exception is raised even if
all the strategies fail. (If the StandardSongPicker is guaranteed to
succeed, then obviously my analysis is wrong.) In this case, then any code
following the for-else will execute. Since this is in a function, and there
doesn't seem to be any following code, that means that your function will
return None instead of a valid picker. Does the rest of your code check for
None before using the picker? If not, you have a bug waiting to bite.

Second, the poor design. When it works as expected, failure is indicated by
AssertionError. Why AssertionError? Why not ImportError, or
UnicodeEncodeError, or ZeroDivisionError, or any other of the dozens of
inappropriate errors that the code could (but shouldn't) raise? I guess
nobody here would write code that looks like this by design:

try:
    picker = select_picker(radio_session, station, artist)
except EOFError:
    handle_no_picker_case()


just because "raise EOFError" required less typing than raising some more
appropriate exception. So why would we write:

try:
    picker = select_picker(radio_session, station, artist)
except AssertionError:
    handle_no_picker_case()


just because "assert" required less typing than raising some more
appropriate exception? assert is not a short-cut for "raise
SomeGenericException". AssertionError has a specific meaning, and it is
sloppy to misuse it. An assertion error means that an assertion has failed,
and assertions only fail when your code contains a logic error or a program
invariant is violated. Both should never happen in production code, and if
they do they ought to be unrecoverable errors.

Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
assertion is checking a function invariant ("one of the strategies will
always succeed") in which case you're doing it exactly right and I should
shut up now :-)


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#62580

FromChris Angelico <rosuav@gmail.com>
Date2013-12-23 14:09 +1100
Message-ID<mailman.4522.1387768642.18130.python-list@python.org>
In reply to#62577
On Mon, Dec 23, 2013 at 1:33 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
> assertion is checking a function invariant ("one of the strategies will
> always succeed") in which case you're doing it exactly right and I should
> shut up now :-)

Or maybe it has a lengthy piece of error trapping code that wasn't
germane to the discussion, and for brevity was squished down to a
quick little assert :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#62592

FromRoy Smith <roy@panix.com>
Date2013-12-22 23:57 -0500
Message-ID<roy-3D1D2D.23572922122013@news.panix.com>
In reply to#62577
In article <52b7a0e4$0$29994$c3e8da3$5496439d@news.astraweb.com>,
 Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:

> Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
> assertion is checking a function invariant ("one of the strategies will
> always succeed") in which case you're doing it exactly right and I should
> shut up now :-)

Yes :-)

More specifically, the assertion exception will get caught way up in 
some django middleware which will log a stack trace and return a HTTP 
50-something.  This will typically be followed by somebody like me 
noticing the stack dump and trying to figure out WTF happened.

Assertions are great tools.  People should use them more often.  In a 
sense, they're executable comments.  They're a programmer's way of 
standing on a hilltop and shouting to all the world, "I swear to you, 
this is true.  There may be a gazillion lines of code out there and 
GBytes of program state, but right here, right now, within this circle 
I've drawn in the sand, I know this to be true, and you can depend on 
that.  You can make it part of the foundation on which you begin to 
reason about program behavior.  Furthermore, if it turns out not to be 
true, you don't have to worry about figuring out who's fault it is.  I 
hereby declare that it's my fault".

[toc] | [prev] | [next] | [standalone]


#62593

FromChris Angelico <rosuav@gmail.com>
Date2013-12-23 16:09 +1100
Message-ID<mailman.4534.1387775349.18130.python-list@python.org>
In reply to#62592
On Mon, Dec 23, 2013 at 3:57 PM, Roy Smith <roy@panix.com> wrote:
> More specifically, the assertion exception will get caught way up in
> some django middleware which will log a stack trace and return a HTTP
> 50-something.  This will typically be followed by somebody like me
> noticing the stack dump and trying to figure out WTF happened.
>
> Assertions are great tools.  People should use them more often.

You do have to be careful though, because they can be compiled out. If
it really is a "can't happen", then sure, but encouraging people to
use them for potentially obscure cases may be dangerous - if you never
happen to hit on it during development and then run with assertions
disabled, you won't see that stack trace.

However, they're still a lot more executable than other forms of comment :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#62623

FromEthan Furman <ethan@stoneleaf.us>
Date2013-12-23 04:45 -0800
Message-ID<mailman.4553.1387804133.18130.python-list@python.org>
In reply to#62592
On 12/22/2013 08:57 PM, Roy Smith wrote:
> In article <52b7a0e4$0$29994$c3e8da3$5496439d@news.astraweb.com>,
>   Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
>
>> Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
>> assertion is checking a function invariant ("one of the strategies will
>> always succeed") in which case you're doing it exactly right and I should
>> shut up now :-)
>
> Yes :-)
>
> More specifically, the assertion exception will get caught way up in
> some django middleware which will log a stack trace and return a HTTP
> 50-something.  This will typically be followed by somebody like me
> noticing the stack dump and trying to figure out WTF happened.

This is completely misusing what assertions are for.  I hope this bit of middleware (or django itself) is very clear 
about never running with assertions turned off.


> Assertions are great tools.

Only when used properly.

>People should use them more often.

I see them being (mis)used too much as it is.

>In a
> sense, they're executable comments.  They're a programmer's way of
> standing on a hilltop and shouting to all the world, "I swear to you,
> this is true.  There may be a gazillion lines of code out there and
> GBytes of program state, but right here, right now, within this circle
> I've drawn in the sand,

Considering how easy it is to disable assertions, a circle in the sand is an amazingly appropriate metaphor.  :)

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#62631

FromRoy Smith <roy@panix.com>
Date2013-12-23 10:10 -0500
Message-ID<roy-67C948.10105023122013@news.panix.com>
In reply to#62623
In article <mailman.4553.1387804133.18130.python-list@python.org>,
 Ethan Furman <ethan@stoneleaf.us> wrote:

> On 12/22/2013 08:57 PM, Roy Smith wrote:
> > In article <52b7a0e4$0$29994$c3e8da3$5496439d@news.astraweb.com>,
> >   Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> >
> >> Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
> >> assertion is checking a function invariant ("one of the strategies will
> >> always succeed") in which case you're doing it exactly right and I should
> >> shut up now :-)
> >
> > Yes :-)
> >
> > More specifically, the assertion exception will get caught way up in
> > some django middleware which will log a stack trace and return a HTTP
> > 50-something.  This will typically be followed by somebody like me
> > noticing the stack dump and trying to figure out WTF happened.
> 
> This is completely misusing what assertions are for.  I hope this bit of 
> middleware (or django itself) is very clear 
> about never running with assertions turned off.

Sigh.  Sometimes I'm not sure which is worse.  The anti-assertion 
zealotry on this list, or the anti-regex zealotry.

The use of an assertion here is perfectly reasonable.  It is a statement 
that "this can never happen".

The bit of middleware I was talking about catches ALL uncaught 
exceptions.  We design our code so that all exceptions are supposed to 
get caught and handled at some appropriate place in application code.  
Nothing is ever supposed to leak up to the point where that middleware 
catches it, and anything caught there is evidence of a bug.  This is a 
common pattern in any kind of long-lived server.

And, if we didn't have the piece of middleware, the assertion (or any 
other uncaught exception) would get caught at some deeper level inside 
the django core.  The result would still be a 500 HTTP response, but 
without the added diagnostic logging we do, so it would be a lot harder 
to understand what happened.

And, if django didn't have that "except Exception" block wrapping 
everything, the gunicorn process would exit and upstart would catch that 
and restart it.

And, yes, I know that assertions get turned off with -O (frankly, I 
think that's a design flaw).  We don't run with -O.

[toc] | [prev] | [next] | [standalone]


#62641

FromEthan Furman <ethan@stoneleaf.us>
Date2013-12-23 08:00 -0800
Message-ID<mailman.4567.1387819120.18130.python-list@python.org>
In reply to#62631
On 12/23/2013 07:10 AM, Roy Smith wrote:
> In article <mailman.4553.1387804133.18130.python-list@python.org>,
>   Ethan Furman <ethan@stoneleaf.us> wrote:
>
>> On 12/22/2013 08:57 PM, Roy Smith wrote:
>>> In article <52b7a0e4$0$29994$c3e8da3$5496439d@news.astraweb.com>,
>>>    Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
>>>
>>>> Anyway, I may be completely misinterpreting what I'm reading. Perhaps the
>>>> assertion is checking a function invariant ("one of the strategies will
>>>> always succeed") in which case you're doing it exactly right and I should
>>>> shut up now :-)
>>>
>>> Yes :-)
>>>
>>> More specifically, the assertion exception will get caught way up in
>>> some django middleware which will log a stack trace and return a HTTP
>>> 50-something.  This will typically be followed by somebody like me
>>> noticing the stack dump and trying to figure out WTF happened.
>>
>> This is completely misusing what assertions are for.  I hope this bit of
>> middleware (or django itself) is very clear
>> about never running with assertions turned off.
>
> Sigh.  Sometimes I'm not sure which is worse.  The anti-assertion
> zealotry on this list, or the anti-regex zealotry.

I am not a zealot (I'm not!  Really!! ;) .  I just find it alarming to have major pieces of software rely on a feature 
that can be so easily tuned out, and it wasn't clear from your comment that it was /any/ exception.

Mostly I don't want newbies thinking "Hey!  I can use assertions for all my confidence testing!"

Just as one data point OpenERP, which has a lot of good features, unfortunately uses assert to test user input.  :(

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#62760

FromRoy Smith <roy@panix.com>
Date2013-12-26 20:37 -0500
Message-ID<roy-CEC4D2.20374026122013@news.panix.com>
In reply to#62641
In article <mailman.4567.1387819120.18130.python-list@python.org>,
 Ethan Furman <ethan@stoneleaf.us> wrote:

> Mostly I don't want newbies thinking "Hey!  I can use assertions for all my 
> confidence testing!"

How about this one, that I wrote yesterday;

        assert second >= self.current_second, "time went backwards"

I think that's pretty high up on the "can never happen" list.

[toc] | [prev] | [next] | [standalone]


#62761

FromChris Angelico <rosuav@gmail.com>
Date2013-12-27 12:44 +1100
Message-ID<mailman.4643.1388108992.18130.python-list@python.org>
In reply to#62760
On Fri, Dec 27, 2013 at 12:37 PM, Roy Smith <roy@panix.com> wrote:
> In article <mailman.4567.1387819120.18130.python-list@python.org>,
>  Ethan Furman <ethan@stoneleaf.us> wrote:
>
>> Mostly I don't want newbies thinking "Hey!  I can use assertions for all my
>> confidence testing!"
>
> How about this one, that I wrote yesterday;
>
>         assert second >= self.current_second, "time went backwards"
>
> I think that's pretty high up on the "can never happen" list.

assert second >= self.current_second, "user changed the clock"

ChrisA

[toc] | [prev] | [next] | [standalone]


#62762

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2013-12-26 21:20 -0500
Message-ID<mailman.4644.1388110844.18130.python-list@python.org>
In reply to#62760
On Fri, 27 Dec 2013 12:44:35 +1100, Chris Angelico <rosuav@gmail.com>
declaimed the following:

>On Fri, Dec 27, 2013 at 12:37 PM, Roy Smith <roy@panix.com> wrote:
>> How about this one, that I wrote yesterday;
>>
>>         assert second >= self.current_second, "time went backwards"
>>
>> I think that's pretty high up on the "can never happen" list.
>
>assert second >= self.current_second, "user changed the clock"
>
	Why blame the user if an NTP synch made the adjustment? <G>
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [next] | [standalone]


#62763

FromChris Angelico <rosuav@gmail.com>
Date2013-12-27 13:27 +1100
Message-ID<mailman.4645.1388111765.18130.python-list@python.org>
In reply to#62760
On Fri, Dec 27, 2013 at 1:20 PM, Dennis Lee Bieber
<wlfraed@ix.netcom.com> wrote:
> On Fri, 27 Dec 2013 12:44:35 +1100, Chris Angelico <rosuav@gmail.com>
> declaimed the following:
>
>>On Fri, Dec 27, 2013 at 12:37 PM, Roy Smith <roy@panix.com> wrote:
>>> How about this one, that I wrote yesterday;
>>>
>>>         assert second >= self.current_second, "time went backwards"
>>>
>>> I think that's pretty high up on the "can never happen" list.
>>
>>assert second >= self.current_second, "user changed the clock"
>>
>         Why blame the user if an NTP synch made the adjustment? <G>

True, it could have been NTP, or maybe the original assert was right
and we're on the other side of an event horizon. But it's much more
fun to blame the user.

ChrisA

[toc] | [prev] | [next] | [standalone]


#62765

FromRoy Smith <roy@panix.com>
Date2013-12-26 23:29 -0500
Message-ID<roy-4A039A.23293026122013@news.panix.com>
In reply to#62763
In article <mailman.4645.1388111765.18130.python-list@python.org>,
 Chris Angelico <rosuav@gmail.com> wrote:

> On Fri, Dec 27, 2013 at 1:20 PM, Dennis Lee Bieber
> <wlfraed@ix.netcom.com> wrote:
> > On Fri, 27 Dec 2013 12:44:35 +1100, Chris Angelico <rosuav@gmail.com>
> > declaimed the following:
> >
> >>On Fri, Dec 27, 2013 at 12:37 PM, Roy Smith <roy@panix.com> wrote:
> >>> How about this one, that I wrote yesterday;
> >>>
> >>>         assert second >= self.current_second, "time went backwards"
> >>>
> >>> I think that's pretty high up on the "can never happen" list.
> >>
> >>assert second >= self.current_second, "user changed the clock"
> >>
> >         Why blame the user if an NTP synch made the adjustment? <G>
> 
> True, it could have been NTP, or maybe the original assert was right
> and we're on the other side of an event horizon. But it's much more
> fun to blame the user.
> 
> ChrisA

NTP is never supposed to move the clock backwards.  If your system clock 
is fast, it's supposed to reduce the rate your clock runs until it's 
back in sync.  Well, maybe it only does that for small corrections?

[toc] | [prev] | [next] | [standalone]


Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →

Back to top | Article view | comp.lang.python


csiph-web