How to invoke a lispy vector in Python statement by using py4cl?
cl-03 opened this issue · 5 comments
Have defined a vector in lisp:
CL-USER> test-excel
#((A B C) (G H J) (5 6 7))
Want to use it like the Python statement:
data = [
['Apples', 10000, 5000, 8000, 6000],
['Pears', 2000, 3000, 4000, 5000],
['Bananas', 6000, 6000, 6500, 6000],
['Oranges', 500, 300, 200, 700],
]
first imagined and tried which didn't work:
CL-USER> (py4cl:python-eval "data =" (py4cl::pythonize test-excel) )
; Evaluation aborted on #<PY4CL:PYTHON-ERROR {100E161CB3}>.
CL-USER> (py4cl:python-eval "data =" (py4cl::pythonize test-excel) "" )
; Evaluation aborted on #<PY4CL:PYTHON-ERROR {100E309773}>.
CL-USER> (py4cl:python-eval "data =" test-excel "" )
; Evaluation aborted on #<PY4CL:PYTHON-ERROR {100E4D25F3}>.
CL-USER> (py4cl:python-eval "data =" test-excel )
; Evaluation aborted on #<PY4CL:PYTHON-ERROR {100E67A593}>.
CL-USER> (py4cl:chain "data =" test-excel )
; Evaluation aborted on #<PY4CL:PYTHON-ERROR {100E822B63}>.
Would you mind teaching me about How to achieve this goal?
This is another instance of using python-exec
rather than python-eval
:
CL-USER> (py4cl:python-exec "data = " #((A B C) (G H J) (5 6 7)))
NIL
CL-USER> (py4cl:python-eval "data")
#((:A :B :C) (:G :H :J) (5 6 7))
Also, do you mind moving over to someplace else, say discord (I'm at digikar99#8835)? These How-Tos seem unsuitable for Issues.
It works,thank you very much ,and Thank you for your advice。
CL-USER> (py4cl:python-exec "data = " test-excel)
NIL
CL-USER> (py4cl:python-eval "data")
#((:A :B :C) (:G :H :J) (5 6 7))
Thanks @digikar99 ! Is there some way we can cover over python's exec
vs eval
? It's not very lispy to have to distinguish between statements and expressions.
Perhaps in python-eval
, we first try eval
. If that raises a SyntaxError
then try exec
. If the given code really contains a syntax error then it will be raised and returned by the exec
. This would probably enable eval
to work, but with some hidden performance cost that isn't clear to the user.
Alternatively, maybe we could just make the error more helpful, adding a suggestion to try python-exec
?
I think the most simple non-breaking change would be to improve the error message to suggest user to try exec
vs eval
, may be a cerror
even!
About a single way that does both exec and eval - perhaps using ast.parse(src_code, mode="eval")
is cleaner (source: https://stackoverflow.com/a/57508838/8957330).
The performance penalty -
def bar(src, t):
start = time.time()
for i in range(t):
exec(src)
return time.time() - start
def foo(src, t):
start = time.time()
for i in range(t):
exec(compile(ast.parse(src), filename="<ast>", mode="exec"))
return time.time() - start
bar("a=5", 10000)
runs almost twice as fast as foo. Similar performance ratio for the string: "def foobar(a,b,c): return 'hello' + a + b * c"
.
Or include a configuration variable or compiler macros to check policy-quality to decide whether to parse!
In my humble opinions,maybe we can define a wrap to invoke exc or eval automatically。
(defun wrap-of-handle (expr)
(try eval)
(if error
(try exc)
(return result-of-eval)))