By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,679 Members | 1,500 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,679 IT Pros & Developers. It's quick & easy.

catching exceptions from an except: block

P: n/a
Hi all,

Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

Here are three ways I can think of doing it:

----------
# This one looks ugly
def nested_first(x):
try:
return a(x)
except:
try:
return b(x)
except:
try:
return c(x)
except:
raise CantDoIt

# This one looks long-winded
def flat_first(x):
try:
return a(x)
except:
pass
try:
return b(x)
except:
pass
try:
return c(x)
except:
raise CantDoIt

# This one only works because a,b,c are functions
# Moreover it seems like an abuse of a loop construct to me
def rolled_first(x):
for f in a, b, c:
try:
return f(x)
except:
continue
raise CantDoIt
----------

I don't feel happy with any of these. Is there a more satisfying way
of doing this in Python? What I would like is something like:

----------
# This one isn't correct but looks the clearest to me
def wished_first(x):
try:
return a(x)
except:
return b(x)
except:
return c(x)
except:
raise CantDoIt
----------

I guess what I'm looking for is some sort of
if:
elif:
....
elif:
else:

but for try: except:
That's why
try:
except:
except:
....
except:

seemed natural to me :) And I'd like to find a nice way to do this in
a syntactically correct way.

Note: I've chosen functions a, b, c, but really I'm looking for a way
that is suitable for any chunk of code.

Mar 7 '07 #1
Share this Question
Share on Google+
35 Replies


P: n/a
Hello Arnaud,
Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.
Exceptions are for error handling, not flow control.
Here are three ways I can think of doing it:
...
# This one only works because a,b,c are functions
# Moreover it seems like an abuse of a loop construct to me
def rolled_first(x):
for f in a, b, c:
try:
return f(x)
except:
continue
raise CantDoIt
My vote is for that one.
I don't feel happy with any of these. Is there a more satisfying way
of doing this in Python? What I would like is something like:

----------
# This one isn't correct but looks the clearest to me
def wished_first(x):
try:
return a(x)
except:
return b(x)
except:
return c(x)
except:
raise CantDoIt
Again, exception are for error handling, not for flow control.

As a side note, try to avoid "catch:", always catch explicit
exceptions.

HTH,
Miki <mi*********@gmail.com>
http://pythonwise.blogspot.com

Mar 7 '07 #2

P: n/a
On 7 Mar, 19:26, "Miki" <miki.teb...@gmail.comwrote:
Hello Arnaud,
Hi Miki

[snip]
Exceptions are for error handling, not flow control.
Maybe but it's not always that clear cut! As error handling is a form
of flow control the two have to meet somewhere.

[snip]
As a side note, try to avoid "catch:", always catch explicit
exceptions.
I didn't specify what I wanted to catch because it didn't feel it was
relevant to the problem.

Thanks

--
Arnaud

Mar 7 '07 #3

P: n/a
In <11**********************@8g2000cwh.googlegroups.c om>, Arnaud Delobelle
wrote:
# This one only works because a,b,c are functions
# Moreover it seems like an abuse of a loop construct to me
def rolled_first(x):
for f in a, b, c:
try:
return f(x)
except:
continue
raise CantDoIt
----------
Why do you think this is an abuse? I think it's a perfectly valid use of
a loop.

Ciao,
Marc 'BlackJack' Rintsch
Mar 7 '07 #4

P: n/a
In <11**********************@p10g2000cwp.googlegroups .com>, Miki wrote:
Exceptions are for error handling, not flow control.
That's not true, they are *exceptions* not *errors*. They are meant to
signal exceptional situations. And at least under the cover it's used in
every ``for``-loop because the end condition is signaled by a
`StopIteration` exception. Looks like flow control to me.

Ciao,
Marc 'BlackJack' Rintsch
Mar 7 '07 #5

P: n/a
Arnaud Delobelle wrote:
Hi all,

Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

Here are three ways I can think of doing it:

----------
# This one looks ugly
def nested_first(x):
try:
return a(x)
except:
try:
return b(x)
except:
try:
return c(x)
except:
raise CantDoIt

# This one looks long-winded
def flat_first(x):
try:
return a(x)
except:
pass
try:
return b(x)
except:
pass
try:
return c(x)
except:
raise CantDoIt

# This one only works because a,b,c are functions
# Moreover it seems like an abuse of a loop construct to me
def rolled_first(x):
for f in a, b, c:
try:
return f(x)
except:
continue
raise CantDoIt
----------

I don't feel happy with any of these. Is there a more satisfying way
of doing this in Python? What I would like is something like:

----------
# This one isn't correct but looks the clearest to me
def wished_first(x):
try:
return a(x)
except:
return b(x)
except:
return c(x)
except:
raise CantDoIt
----------

I guess what I'm looking for is some sort of
if:
elif:
...
elif:
else:

but for try: except:
That's why
try:
except:
except:
...
except:

seemed natural to me :) And I'd like to find a nice way to do this in
a syntactically correct way.

Note: I've chosen functions a, b, c, but really I'm looking for a way
that is suitable for any chunk of code.
Without knowing more about the functions and the variable it is somewhat
hard to tell what you are trying to accomplish. If a, b, c are functions
that act on x when it is a different type, change to one function that
can handle all types.

def d(x):
if isinstance(x, basestring):
#
# Code here for string
#
elif isinstance(x, int):
#
# Code here for int
#
elif isinstance(x, float):
#
# Code here for string
#
else:
raise ValueError
If they are different functions based on type do something like this:

#
# Set up a dictionary with keys for different types and functions
# that correspond.
#
fdict={type(''): a, type(1): b, type(1.0): c}
#
# Call the appropriate function based on type
#
fdict[type(x)](x)

-Larry
Mar 7 '07 #6

P: n/a
Miki a écrit :
Hello Arnaud,

>>Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

Exceptions are for error handling, not flow control.
def until(iterable,sentinel):
for item in iterable:
if item == sentinel:
raise StopIteration
yield item
>>for item in until(range(10), 5):
.... print item
....
0
1
2
3
4
>>>
Exceptions *are* a form of flow control.
Mar 7 '07 #7

P: n/a
Larry Bates a écrit :
(snip)
def d(x):
if isinstance(x, basestring):
#
# Code here for string
#
elif isinstance(x, int):
#
# Code here for int
#
elif isinstance(x, float):
#
# Code here for string
#
else:
raise ValueError
As a side note : While there are a few corner cases where this is hardly
avoidable (and yet I'd rather test on interface, not on concrete type),
this kind of cose is exactly what OO polymorphic dispatch is supposed to
avoid (no, don't tell me: I know you can't easily add methods to most
builtin types).
Mar 7 '07 #8

P: n/a
En Wed, 07 Mar 2007 19:00:59 -0300, Bruno Desthuilliers
<bd*****************@free.quelquepart.frescribió :
this kind of cose is exactly what OO polymorphic dispatch is supposed to
this kind of cose? Ce genre de chose?

--
Gabriel Genellina

Mar 7 '07 #9

P: n/a
On Mar 7, 8:52 pm, Larry Bates <lba...@websafe.comwrote:
[snip]
Without knowing more about the functions and the variable it is somewhat
hard to tell what you are trying to accomplish. If a, b, c are functions
that act on x when it is a different type, change to one function that
can handle all types.
I'm not really thinking about this situation so let me clarify. Here
is a simple concrete example, taking the following for the functions
a,b,c I mention in my original post.
- a=int
- b=float
- c=complex
- x is a string
This means I want to convert x to an int if possible, otherwise a
float, otherwise a complex, otherwise raise CantDoIt.

I can do:

for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.

--
Arnaud

Mar 7 '07 #10

P: n/a
Arnaud Delobelle a écrit :
Hi all,

Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

Here are three ways I can think of doing it:

----------
# This one looks ugly
Yes.
def nested_first(x):
try:
return a(x)
except:
<side-note>
Try avoiding bare except clauses. It's usually way better to specify the
type(s) of exception you're expecting to catch, and let other propagate.
</side-note>
try:
return b(x)
except:
try:
return c(x)
except:
raise CantDoIt

# This one looks long-winded
Yes. And not's very generic.
def flat_first(x):
try:
return a(x)
except:
pass
try:
return b(x)
except:
pass
try:
return c(x)
except:
raise CantDoIt

# This one only works because a,b,c are functions
It works with any callable. Anyway, what else would you use here ???
# Moreover it seems like an abuse of a loop construct to me
Why so ? loops are made for looping, adn functions are objects like any
other.
def rolled_first(x):
for f in a, b, c:
try:
return f(x)
except:
continue
raise CantDoIt
Here's an attempt at making it a bit more generic (<side-note>it still
lacks a way to specify which kind of exceptions should be silently
swallowed</side-note>.

def trythese(*functions):
def try_(*args, **kw):
for func in functions:
try:
return func(*args, **kw)
except: # FIX ME : bare except clause
pass
else:
# really can't do it, sorry
raise CantDoIt
return try_

result = trythese(a, b, c)(x)
----------
# This one isn't correct but looks the clearest to me
def wished_first(x):
try:
return a(x)
except:
return b(x)
except:
return c(x)
except:
raise CantDoIt
Having multiple except clauses is correct - but it has another semantic.

Note: I've chosen functions a, b, c, but really I'm looking for a way
that is suitable for any chunk of code.
A function is an object wrapping a chunk of code...

I personnaly find the loop-based approach quite clean and pythonic.
Mar 7 '07 #11

P: n/a
On Mar 7, 2:48 pm, "Arnaud Delobelle" <arno...@googlemail.comwrote:
>
I'm not really thinking about this situation so let me clarify. Here
is a simple concrete example, taking the following for the functions
a,b,c I mention in my original post.
- a=int
- b=float
- c=complex
- x is a string
This means I want to convert x to an int if possible, otherwise a
float, otherwise a complex, otherwise raise CantDoIt.

I can do:

for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.

--
Arnaud
Wouldn't it be easier to do:

if isinstance(x, int):
# do something
elif isinstance(x, float)t:
# do something
elif isinstance(x, complex):
# do something
else:
raise CantDoIt

or,

i = [int, float, complex]
for f in i:
if isinstance(x, f):
return x
else:
raise CantDoIt

Mar 7 '07 #12

P: n/a
Gabriel Genellina a écrit :
En Wed, 07 Mar 2007 19:00:59 -0300, Bruno Desthuilliers
<bd*****************@free.quelquepart.frescribió :
>this kind of cose is exactly what OO polymorphic dispatch is supposed to


this kind of cose?
sorry
s/cose/code/
Ce genre de chose?
En quelques sortes, oui, quoique pas tout à fait !-)
Mar 7 '07 #13

P: n/a
On Mar 7, 3:04 pm, garri...@gmail.com wrote:
On Mar 7, 2:48 pm, "Arnaud Delobelle" <arno...@googlemail.comwrote:


I'm not really thinking about this situation so let me clarify. Here
is a simple concrete example, taking the following for the functions
a,b,c I mention in my original post.
- a=int
- b=float
- c=complex
- x is a string
This means I want to convert x to an int if possible, otherwise a
float, otherwise a complex, otherwise raise CantDoIt.
I can do:
for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt
But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.
--
Arnaud

Wouldn't it be easier to do:

if isinstance(x, int):
# do something
elif isinstance(x, float)t:
# do something
elif isinstance(x, complex):
# do something
else:
raise CantDoIt

or,

i = [int, float, complex]
for f in i:
if isinstance(x, f):
return x
else:
raise CantDoIt
I so missed the point of this. Not my day. Please ignore my post.

Mar 7 '07 #14

P: n/a
En Wed, 07 Mar 2007 18:48:18 -0300, Arnaud Delobelle
<ar*****@googlemail.comescribió:
for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.
Hmmm, functions are cheap - nobody is charging you $2 for each "def"
statement you write, I presume :)

A bit more serious, if those "chunks of code" are processing its input and
returning something that you further process... they *are* functions. If
you don't want them to be publicly available, use inner functions:

def xxxfactory(x):
def f1(x):
...
def f2(x):
...
def f3(x):
...

for f in f1,f2,f3:
try:
return f(x)
... same as above...

--
Gabriel Genellina

Mar 7 '07 #15

P: n/a
Arnaud Delobelle a écrit :
On Mar 7, 8:52 pm, Larry Bates <lba...@websafe.comwrote:
[snip]
>>Without knowing more about the functions and the variable it is somewhat
hard to tell what you are trying to accomplish. If a, b, c are functions
that act on x when it is a different type, change to one function that
can handle all types.


I'm not really thinking about this situation so let me clarify. Here
is a simple concrete example, taking the following for the functions
a,b,c I mention in my original post.
- a=int
- b=float
- c=complex
- x is a string
This means I want to convert x to an int if possible, otherwise a
float, otherwise a complex, otherwise raise CantDoIt.

I can do:

for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions
You have to write the "chunks of code" anyway, don't you ? So just
adding a def statement above each chunk is not such a big deal.

Remember that you can define nested funcs, that will close over the
namespace of the enclosing one, so you dont necessarily have to pollute
the global namespace nor explicitly pass the whole environment to each
of these functions.

Using the generic higher order func I proposed in a previous answer:

def maincode(tati, pouffin):
def a():
# some
# code
# here
# that may raise
return foo

def b():
# some
# shorter chunk
return bar

def c():
# yet
# some
# other
# code
return quux

return trythese(a, b)()

Is it really less readable than:

def maincode(tati, pouffin):
try:
# some
# code
# here
# that may raise
return foo

except_retry: # the missing(???) keyword you're after
# some
# shorter chunk
return bar

except_retry:
# yet
# some
# other
# code
return quux

else:
raise CantDoIt

simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.

--
Arnaud
Mar 7 '07 #16

P: n/a
Gabriel Genellina a écrit :
En Wed, 07 Mar 2007 18:48:18 -0300, Arnaud Delobelle
<ar*****@googlemail.comescribió:
>for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs'). Besides I am not happy
with the other two idioms I can think of.


Hmmm, functions are cheap
To define. You pay the price when you call them !-)

(sorry, couldn't resist - I otherwise totally agree with you)

Mar 7 '07 #17

P: n/a
Arnaud Delobelle schrieb:
On Mar 7, 8:52 pm, Larry Bates <lba...@websafe.comwrote:
[snip]
>Without knowing more about the functions and the variable it is somewhat
hard to tell what you are trying to accomplish. If a, b, c are functions
that act on x when it is a different type, change to one function that
can handle all types.

I'm not really thinking about this situation so let me clarify. Here
is a simple concrete example, taking the following for the functions
a,b,c I mention in my original post.
- a=int
- b=float
- c=complex
- x is a string
This means I want to convert x to an int if possible, otherwise a
float, otherwise a complex, otherwise raise CantDoIt.

I can do:

for f in int, float, complex:
try:
return f(x)
except ValueError:
continue
raise CantDoIt

But if the three things I want to do are not callable objects but
chunks of code this method is awkward because you have to create
functions simply in order to be able to loop over them (this is whay I
was talking about 'abusing loop constructs').
In your case, I don't consider it an abuse - au contraire. Because in
such a situation where a possibly growing number of functions dealing
with one value until one of them "fits" a loop is the natural thing to
do, as it won't change in appearance just because you add a new
conversion-function to some (semi-)global list. I'd consider it
especially good style in that case.

Diez
Mar 7 '07 #18

P: n/a
On Mar 7, 4:58 pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
except_retry: # the missing(???) keyword you're after
What is 'except_retry'?

To the OP, with the loop and the callables you could also break out of
the loop when the condition is met and use the else condition to raise
the exception.

def test(arg):
for f in int, float, str, hex:
try:
return f(arg)
break # breaks on f==str
except:
pass
else:
raise ValueError # remove str above to see this
print test('^&%')

Regards,
Jordan
Mar 8 '07 #19

P: n/a
On Wed, 07 Mar 2007 10:32:53 -0800, Arnaud Delobelle wrote:
Hi all,

Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

Here are three ways I can think of doing it:

----------
# This one looks ugly
def nested_first(x):
try:
return a(x)
except:
try:
return b(x)
except:
try:
return c(x)
except:
raise CantDoIt

Exceptions are great, but sometimes they get in the way. This is one of
those times.

NULL = object() # get a unique value
def result_or_special(func, x):
"""Returns the result of func(x) or NULL."""
try:
return func(x)
except Exception:
return NULL

def failer(x):
"""Always fail."""
raise CantDoIt

def function(x):
funcs = (a, b, c, failer)
for func in funcs:
result = func(x)
if result is not NULL: break
return result
Or if you prefer:

def function(x):
NULL = object()
funcs = (a, b, c)
for func in funcs:
try:
result = func(x)
except Exception:
pass
else:
break
else:
# we didn't break out of the loop
raise CantDoIt
# we did break out of the loop
return result

--
Steven D'Aprano

Mar 8 '07 #20

P: n/a
MonkeeSage a écrit :
On Mar 7, 4:58 pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
> except_retry: # the missing(???) keyword you're after

What is 'except_retry'?
A totally imaginary statement that would do what the OP is looking for.
To the OP, with the loop and the callables you could also break out of
the loop when the condition is met and use the else condition to raise
the exception.

def test(arg):
for f in int, float, str, hex:
try:
return f(arg)
break # breaks on f==str
You don't need to break here since you're returning.
except:
pass
else:
raise ValueError # remove str above to see this
Mar 8 '07 #21

P: n/a
On Mar 7, 7:32 pm, "Arnaud Delobelle" <arno...@googlemail.comwrote:
Hi all,

Imagine I have three functions a(x), b(x), c(x) that each return
something or raise an exception. Imagine I want to define a function
that returns a(x) if possible, otherwise b(x), otherwise c(x),
otherwise raise CantDoIt.

(This is my first decorator.) You could also just raise your custom
exception rather than having a "retval". Other variations I'm sure are
possible. HTH.
import exceptions

class ABCException(exceptions.Exception):
pass

def onfail(retval):
def outer(fn):
def inner(*args, **kwargs):
try:
return fn(*args, **kwargs)
except:
return retval
return inner
return outer

@onfail(False)
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise

@onfail(False)
def b(x):
if x == 2:
return 'function b succeeded'
else:
raise

@onfail(False)
def c(x):
if x == 3:
return 'function c succeeded'
else:
raise

def doit(x):
for f in [a, b, c]:
result = f(x)
if result:
return result
raise ABCException()

print doit(1)
print doit(2)
print doit(3)
print doit(4)

---------------------------

function a succeeded
function b succeeded
function c succeeded
Traceback (most recent call last):
File "\working\scratch.py", line 48, in ?
print doit(4)
File "\working\scratch.py", line 43, in doit
raise ABCException()
__main__.ABCException
shell returned 1


Mar 8 '07 #22

P: n/a
En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan
<gr********@yahoo.co.ukescribió:
@onfail(False)
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise
I know it's irrelevant, as you use a bare except, but such raise looks a
bit ugly...

--
Gabriel Genellina

Mar 8 '07 #23

P: n/a
On Thu, 08 Mar 2007 06:31:20 -0300, Gabriel Genellina wrote:
En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan
<gr********@yahoo.co.ukescribió:
>@onfail(False)
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise

I know it's irrelevant, as you use a bare except, but such raise looks a
bit ugly...

I thought "raise" on its own was supposed to re-raise the previous
exception, but I've just tried it in the interactive interpreter and it
doesn't work for me.
>>raise ValueError # prime a "previous exception"
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError
>>raise # re-raise the previous exception?
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: exceptions must be classes, instances, or strings (deprecated), not NoneType
Have I misunderstood?

--
Steven D'Aprano

Mar 9 '07 #24

P: n/a
Steven D'Aprano <st***@REMOVEME.cybersource.com.auwrites:
I thought "raise" on its own was supposed to re-raise the previous
exception, but I've just tried it in the interactive interpreter and it
doesn't work for me.
It means you can catch an exception, do stuff with it, and then pass
it upward to earlier callers:

def foo(n):
try:
bar(n)
except (ValueError, TypeError):
print "invalid n:", n
raise # re-signal the same error to foo's caler
Mar 9 '07 #25

P: n/a
On Thu, 08 Mar 2007 16:19:27 -0800, Paul Rubin wrote:
Steven D'Aprano <st***@REMOVEME.cybersource.com.auwrites:
>I thought "raise" on its own was supposed to re-raise the previous
exception, but I've just tried it in the interactive interpreter and it
doesn't work for me.

It means you can catch an exception, do stuff with it, and then pass
it upward to earlier callers:
[snip code]

Are you saying it only works as advertised within the except clause of a
try...except block?

--
Steven D'Aprano

Mar 9 '07 #26

P: n/a
Steven D'Aprano <st***@REMOVEME.cybersource.com.auwrites:
Are you saying it only works as advertised within the except clause of a
try...except block?
I think that's the idea. It hadn't occurred to me that it could be
used any other way, but I don't have the docs in front of me right
now, so maybe I missed something.
Mar 9 '07 #27

P: n/a
En Thu, 08 Mar 2007 21:11:54 -0300, Steven D'Aprano
<st***@REMOVEME.cybersource.com.auescribió:
>>@onfail(False)
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise

I thought "raise" on its own was supposed to re-raise the previous
exception, but I've just tried it in the interactive interpreter and it
doesn't work for me.
Not the *previous* exception, but the *current* one. You must be inside an
"except" clause to use a bare raise.

--
Gabriel Genellina

Mar 9 '07 #28

P: n/a
On Mar 8, 10:31 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan
<grflana...@yahoo.co.ukescribió:
@onfail(False)
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise

I know it's irrelevant, as you use a bare except, but such raise looks a
bit ugly...

--
Gabriel Genellina
Agreed. I thought a 'gentle reader' could have filled in the blanks,
but I suppose I should have taken the time to put in a custom
exception.

Another version:

import exceptions

class ABCException(exceptions.Exception):
pass

class DoItException(exceptions.Exception):
pass

def onfailFalse(fn):
def inner(*args, **kwargs):
try:
return fn(*args, **kwargs)
except ABCException:
return False
return inner

@onfailFalse
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise ABCException()

@onfailFalse
def b(x):
if x == 2:
return 'function b succeeded'
else:
raise ABCException()

@onfailFalse
def c(x):
if x == 3:
return 'function c succeeded'
else:
raise ABCException()

def doit(x):
for f in [a, b, c]:
result = f(x)
if result:
return result
raise DoItException()

print doit(1)
print doit(2)
print doit(3)
print doit(4)

Mar 9 '07 #29

P: n/a
"Gabriel Genellina" <ga*******@yahoo.com.arwrote:
Not the *previous* exception, but the *current* one. You must be
inside an "except" clause to use a bare raise.
No, you don't have to be inside an except clause to use a bare raise.

A bare 'raise' will re-raise the last exception that was active in the
current scope. That applies even outside the except clauses just so long
as there has been an exception within the same function:

e.g.

def retry(fn, *args):
for attempt in range(3):
try:
return fn(*args)
except:
print "retrying attempt", attempt+1
# If we get here we've had too many retries
raise
>>import random
def testfn():
if random.randint(0,3):
raise RuntimeError("oops")
return 42
>>retry(testfn)
retrying attempt 1
retrying attempt 2
retrying attempt 3

Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
retry(testfn)
File "<pyshell#20>", line 4, in retry
return fn(*args)
File "<pyshell#23>", line 3, in testfn
raise RuntimeError("oops")
RuntimeError: oops
>>retry(testfn)
retrying attempt 1
retrying attempt 2
42
>>retry(testfn)
42
Mar 9 '07 #30

P: n/a
En Fri, 09 Mar 2007 04:49:59 -0300, Gerard Flanagan
<gr********@yahoo.co.ukescribió:
Another version:

import exceptions
As back in time as I could go (Python 1.5), exceptions were available as
builtins...
def onfailFalse(fn):
def inner(*args, **kwargs):
try:
return fn(*args, **kwargs)
except ABCException:
return False
return inner

@onfailFalse
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise ABCException()
There is a serious flaw on this approach, the function can't return any
false value (it would be treated as a failure).

--
Gabriel Genellina

Mar 9 '07 #31

P: n/a
En Fri, 09 Mar 2007 05:52:35 -0300, Duncan Booth
<du**********@invalid.invalidescribió:
"Gabriel Genellina" <ga*******@yahoo.com.arwrote:
>Not the *previous* exception, but the *current* one. You must be
inside an "except" clause to use a bare raise.
No, you don't have to be inside an except clause to use a bare raise.
A bare 'raise' will re-raise the last exception that was active in the
current scope. That applies even outside the except clauses just so long
as there has been an exception within the same function:
Oh! Thanks, I didn't know that.
I tested it in the interpreter, outside any function, and the exception
info was lost immediately, so I wrongly concluded that it lived shortly.

--
Gabriel Genellina

Mar 9 '07 #32

P: n/a
On Mar 9, 9:56 am, "Gabriel Genellina" <gagsl-...@yahoo.com.arwrote:
En Fri, 09 Mar 2007 04:49:59 -0300, Gerard Flanagan
<grflana...@yahoo.co.ukescribió:
Another version:
import exceptions

As back in time as I could go (Python 1.5), exceptions were available as
builtins...
I did not know that. Thanks.
def onfailFalse(fn):
def inner(*args, **kwargs):
try:
return fn(*args, **kwargs)
except ABCException:
return False
return inner
@onfailFalse
def a(x):
if x == 1:
return 'function a succeeded'
else:
raise ABCException()

There is a serious flaw on this approach, the function can't return any
false value (it would be treated as a failure).
I was teaching myself decorators more than anything, so it's not
thought out to any extent, but even so I don't think it's a "serious
flaw", rather it would be programmer error to use @onfailFalse on a
function that may return False. Don't you think?

Gerard

Mar 9 '07 #33

P: n/a
En Fri, 09 Mar 2007 07:30:20 -0300, Gerard Flanagan
<gr********@yahoo.co.ukescribió:
>There is a serious flaw on this approach, the function can't return any
false value (it would be treated as a failure).

I was teaching myself decorators more than anything, so it's not
thought out to any extent, but even so I don't think it's a "serious
flaw", rather it would be programmer error to use @onfailFalse on a
function that may return False. Don't you think?
I thought this was on response to the original problem, not for your own
problem.

--
Gabriel Genellina

Mar 9 '07 #34

P: n/a
On Mar 9, 11:57 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
En Fri, 09 Mar 2007 07:30:20 -0300, Gerard Flanagan
<grflana...@yahoo.co.ukescribió:
There is a serious flaw on this approach, the function can't return any
false value (it would be treated as a failure).
I was teaching myself decorators more than anything, so it's not
thought out to any extent, but even so I don't think it's a "serious
flaw", rather it would be programmer error to use @onfailFalse on a
function that may return False. Don't you think?

I thought this was on response to the original problem, not for your own
problem.
Mea culpa.

Gerard

Mar 9 '07 #35

P: n/a
En Fri, 09 Mar 2007 08:14:18 -0300, Gerard Flanagan
<gr********@yahoo.co.ukescribió:
Mea culpa.
Ego te absolvo in nomine Patris Guidii et Filii Python et Spiritus Sancti
Computatorium.

--
Gabriel Genellina

Mar 9 '07 #36

This discussion thread is closed

Replies have been disabled for this discussion.