Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 60 lines
 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.

Created by R K on Wed, 19 Apr 2006 (PSF)
Python recipes (4591)
R K's recipes (5)

Required Modules

Other Information and Tasks