Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An attempt to create a Python expression that acts like the try/except/finally blocks.
maybe:python-spexy siege$ PYTHONPATH=./ python tmp/spexy_try.py
The original spexy source is
-----
(defun division (x y)
(let ((result None))
(try
(setf result (/ x y))
((ZeroDivisionError)
(println "division by zero!" x "/" y)
False)
(:else
(println "result is" result)
result)
(:finally
(println "executing finally clause")))))
-----
parses into tree
-----
['defun', 'division', ['x', 'y'], ['let', [['result', 'None']], ['try', ['setf', 'result', ['/', 'x', 'y']], [['ZeroDivisionError'], ['println', '"division by zero!"', 'x', '"/"', 'y'], 'False'], [':else', ['println', '"result is"', 'result'], 'result'], [':finally', ['println', '"executing finally clause"']]]]]
-----
processed into Python
-----
globals().__setitem__('division', (lambda x, y: ((lambda result: (lambda _lcls:(eval(compile('def try_block(try_clause,except_0,else_clause,finally_clause):\n\tfrom sys import exc_info\n\ttry:\n\t\ttry_clause()\n\texcept (ZeroDivisionError,):\n\t\treturn except_0(*exc_info())\n\telse:\n\t\treturn else_clause()\n\tfinally:\n\t\tfinally_clause()\n','<spexy>','single'),globals(),_lcls), _lcls)[-1])({})['try_block']((lambda : result.__setitem__(0, (x / y))),(lambda exc_type, exc_val, exc_tb: (__import__('sys').stdout.writelines(map(str, ("division by zero!", " ", x, " ", "/", " ", y, '\n'))), False,)[-1]), (lambda : (__import__('sys').stdout.writelines(map(str, ("result is", " ", result[0], '\n'))), result[0],)[-1]), (lambda : __import__('sys').stdout.writelines(map(str, ("executing finally clause", '\n'))))))([None]))))
-----
division(1, 2)
result is 0
executing finally clause
result: 0
division(4, 2)
result is 2
executing finally clause
result: 2
division(2, 0)
division by zero! 2 / 0
executing finally clause
result: False
it works!
from cStringIO import StringIO
import spexy
src = r"""
(defun division (x y)
(let ((result None))
(try
(setf result (/ x y))
((ZeroDivisionError)
(println "division by zero!" x "/" y)
False)
(:else
(println "result is" result)
result)
(:finally
(println "executing finally clause")))))
""".strip()
print "The original spexy source is\n-----\n", src, "\n-----"
print
tree = spexy.build_tree(StringIO(src))[0]
print "parses into tree\n-----\n", tree, "\n-----"
print
pycode = spexy.evaluate(spexy.ns_new(), tree)
print "processed into Python\n-----\n", pycode, "\n-----"
print
# since the spexy code uses defun, this will actually put that
# function in our globals
eval(pycode)
print "division(1, 2)"
result = division(1, 2)
print "result:", result
print
print "division(4, 2)"
result = division(4, 2)
print "result:", result
print
print "division(2, 0)"
result = division(2, 0)
print "result:", result
print
print "it works!"
@obriencj

This comment has been minimized.

Copy link
Owner Author

obriencj commented Jan 25, 2014

So I think what I'd really need to do is eval that with the normal globals() but with a locals that was an empty map; this way I could have the try_block be composed by spexy on a per-try-basis, with each of the possible exception types embedded there. This saves me from having to write my own dispatching-by-type.

I'd also make the various except_clause handler functions accept the triplet from sys.exc_info() rather than require them to mine it themselves.

I have to say that any place where I have to use compile/eval feels like cheating. I wish I could find something that worked like my _try function that already existed in base Python... maybe there is such and I simply haven't found it yet?

@obriencj

This comment has been minimized.

Copy link
Owner Author

obriencj commented Jan 25, 2014

@obriencj

This comment has been minimized.

Copy link
Owner Author

obriencj commented Jan 25, 2014

I need to update the example here, because it doesn't illustrate that the exception handlers automatically get a local binding of exc_type, exc_val, and exc_tb that they can use to work with the exception they're dealing with.

The trycall form is more explicit about this; it requires the handlers to be ternary callables

@obriencj

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.