Recipe/tool for turning exception handling into functional alternation.
try..except clauses make Python source code often clumsy and impact the readablity. This recipe presents a simple functional approach to work with exceptions and finalizations - applicable in a majority of cases.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import sys
def exceptional(func,alt_return=None,alt_exceptions=(Exception,),final=None,catch=None):
"""turns exceptions into alternative return value"""
def _exceptional(*args,**kwargs):
try:
try: return func(*args,**kwargs)
except alt_exceptions:
return alt_return
except:
if catch: return catch(sys.exc_info(), lambda:func(*args,**kwargs))
raise
finally:
if final: final()
return _exceptional
def final(func,final=None,catch=None,alt_exceptions=(),alt_return=None):
"""connects a final call to a function call"""
def _exceptional(*args,**kwargs):
try:
try: return func(*args,**kwargs)
except alt_exceptions:
return alt_return
except:
if catch: return catch(sys.exc_info(), lambda:func(*args,**kwargs))
raise
finally:
if final: final()
return _exceptional
# examples
import os
exceptional( os.mkdir )('log')
print exceptional( list.index )([1,2,3], 4) # None
print exceptional( list.index, -1 )([1,2,3], 4) # -1
print exceptional( lambda:open('?').read(), # :-(
':-(',
(OSError,IOError)) ()
open_e = exceptional(open)
f=open_e('first.txt') or open_e('second.txt') or open('third.txt')
s = final(f.read, f.close) ()
class X:
def f(self):
return 1/0
f=exceptional(f,-1)
@exceptional
def g(self):
return 1/0
def h(self):
return final(lambda:self.myattr,
catch=lambda exc,again:self.create() or again()) ()
def create(self):
self.myattr=1
print X().f()
print X().g()
print X().h()
|
Could be considered for module functional or __builtin__ .
final() does a lot in a functional style, what the new 'with' statement in Py2.5 does with blocks and context classes.