14

I'm trying to run a snippet of Python from within Java, using Jython. If I use an exec statement to import, everything works.

PythonInterpreter pi = new PythonInterpreter();
pi.exec("import re");
PythonObject o = pi.eval("re.match('abc', 'abc123')"); // returns a MatchObject
o = pi.eval("re.match('abc', 'def123')"); // returns Py.None

If, however, I try to combine the two lines, all hell breaks loose. This:

PythonInterpreter pi = new PythonInterpreter();
pi.eval("import re"); // exception!
PythonObject o = pi.eval("re.match('abc', 'abc123')"); // never gets here
o = pi.eval("re.match('abc', 'def123')"); // ....

...throws an exception "no viable alternative at input 'import'", ('<string>',1,0,'import re\n').

This matters, because ideally I'd like to be able to eval a whole script as a single string, without having to break the imports out into a separate part. Am I doing something wrong? Is there another way to tell Jython "take this whole blob of script, including imports, and run it, then give me back a result"? This needs to be at runtime -- pre-compiling the Python into .class files is not an option.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Coderer
  • 25,844
  • 28
  • 99
  • 154
  • I made the title more generic because the same "issue" also occurs with CPython's eval/exec .. just a slightly different error message. –  Aug 09 '12 at 15:23

3 Answers3

19

The problem is that eval evaluates expressions and returns some result, while exec executes statements in some context. import is a statement, while re.match() is an expression.

Rostyslav Dzinko
  • 39,424
  • 5
  • 49
  • 62
  • I see what you mean -- I also can't do `pi.eval("pattern='abc'\nre.match('abc', 'abc123')");` for the same reason. I really need to be able to run a whole script and get a result back -- is that just not possible? – Coderer Aug 09 '12 at 15:32
  • See [the question I linked to](http://stackoverflow.com/questions/1887320/get-data-back-from-jython-scripts-using-jsr-223) in Senthil's answer below to maybe clarify a bit -- I really want a big block of script that evaluates to a single, anonymous result. I could do `pi.exec("pattern='abc'\nresult=re.match('abc', 'abc123')");` followed by `pi.get("result")` but I'd really like to do the Ruby-style anonymous last-executed value thing instead.... – Coderer Aug 09 '12 at 16:06
  • I've accepted this because apparently this difference is the reason why I can't do in Python what I've already done in Ruby and Python. Thanks for clarifying! – Coderer Sep 07 '12 at 09:42
7

Try this,

eval("__import__('re').match('abc', 'abc123')")
user1513192
  • 1,123
  • 4
  • 17
  • 29
  • I should point out that I've oversimplified the example -- I want to be able to specify a longer, complex script and get a final, anonymous return value from it.... – Coderer Aug 13 '12 at 08:10
1

Here what do you mean by the result?

I am assuming that it is some calculated value of your script. According to the documentation of 'exec' the code runs in the current scope. Hence you must be able to access the values of any new symbols that you have created inside exec statement.

a = 20
b = 10
exec("c = a + b")
print c

The above code should print 30.

Senthil Babu
  • 1,243
  • 2
  • 11
  • 20
  • I want a full-fledged, multi-line Python script, that computes a single return value, like you can do in Ruby or Java. Apparently [there's a fundamental difference](http://stackoverflow.com/questions/1887320/get-data-back-from-jython-scripts-using-jsr-223) between those languages and Python -- in short, I want the whole-script-execution to have a single "result" value, but Python just doesn't do that. – Coderer Aug 09 '12 at 16:04
  • I don't get it. Can you give an example in java? – Senthil Babu Aug 09 '12 at 18:33
  • Java doesn't have this construct -- the idea that a "block" of code is a first-class construct and has a value when evaluated. You can see the linked question above, but basically, with other Java scripting frameworks (e.g. Rhino or JRuby), you can `myEngine.eval("a=foo() \n b=bar(a) \n a+3")` and the return value from that method call will be equivalent to `bar(foo())+3`. Since Java doesn't have "blocks", you can't evaluate one. – Coderer Aug 10 '12 at 06:09
  • If it is just a convention that the last expression gives the result, you could simply define your own convention that the result is assigned to some standard name. Eg:- result could be name to which you may assign the result in your script that you evaluate and retrieve it in the main program with the same name. – Senthil Babu Aug 10 '12 at 13:37
  • Senthil: this is what I wound up doing, but I don't like it because the anonymous-return-value convention is already in use for other languages in the project I'm working on. – Coderer Aug 13 '12 at 08:09