bendudson / py4cl

Call python from Common Lisp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to invoke a lispy vector in Python statement by using py4cl?

cl-03 opened this issue · comments

commented

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.

commented

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!

commented

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