catching exceptions from an except: block

  • Thread starter Arnaud Delobelle
  • Start date
B

Bruno Desthuilliers

MonkeeSage a écrit :
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.
 
G

Gerard Flanagan

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
 
G

Gabriel Genellina

En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan
@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...
 
S

Steven D'Aprano

En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan


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.
Traceback (most recent call last):
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: exceptions must be classes, instances, or strings (deprecated), not NoneType


Have I misunderstood?
 
P

Paul Rubin

Steven D'Aprano said:
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
 
S

Steven D'Aprano

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?
 
P

Paul Rubin

Steven D'Aprano said:
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.
 
G

Gabriel Genellina

En Thu, 08 Mar 2007 21:11:54 -0300, Steven D'Aprano
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.
 
G

Gerard Flanagan

En Thu, 08 Mar 2007 06:17:37 -0300, Gerard Flanagan


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

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)
 
D

Duncan Booth

Gabriel Genellina said:
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
if random.randint(0,3):
raise RuntimeError("oops")
return 42
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: oopsretrying attempt 1
retrying attempt 2
4242
 
G

Gabriel Genellina

En Fri, 09 Mar 2007 04:49:59 -0300, Gerard Flanagan
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).
 
G

Gabriel Genellina

En Fri, 09 Mar 2007 05:52:35 -0300, Duncan Booth
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.
 
G

Gerard Flanagan

En Fri, 09 Mar 2007 04:49:59 -0300, Gerard Flanagan



As back in time as I could go (Python 1.5), exceptions were available as
builtins...

I did not know that. Thanks.
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
 
G

Gabriel Genellina

En Fri, 09 Mar 2007 07:30:20 -0300, Gerard Flanagan
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.
 
G

Gerard Flanagan

En Fri, 09 Mar 2007 07:30:20 -0300, Gerard Flanagan



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

Mea culpa.

Gerard
 
G

Gabriel Genellina

En Fri, 09 Mar 2007 08:14:18 -0300, Gerard Flanagan
Mea culpa.

Ego te absolvo in nomine Patris Guidii et Filii Python et Spiritus Sancti
Computatorium.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top