Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #62541 > unrolled thread
| Started by | Frank Cui <ycui@outlook.com> |
|---|---|
| First post | 2013-12-22 15:37 -0300 |
| Last post | 2013-12-23 15:22 +0000 |
| Articles | 20 on this page of 67 — 18 participants |
Back to article view | Back to comp.lang.python
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 →
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2013-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]
| From | Rick Johnson <rantingrickjohnson@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Ned Batchelder <ned@nedbatchelder.com> |
|---|---|
| Date | 2013-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]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2013-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Dennis Lee Bieber <wlfraed@ix.netcom.com> |
|---|---|
| Date | 2013-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-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]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-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