简体   繁体   中英

Emulate Python shell's “return value” behaviour

Let's imagine I have a JSON list of Python strings to evaluate. For example, maybe I am building a client-server Python GUI.

One convenient thing about the regular Python interpreter is that it shows the "pseudo-return value" of each line, like this:

 $ python3 -c "import code; code.interact()"
 Python 3.7.7 (default, Mar 10 2020, 15:43:03) 
 (InteractiveConsole)
 >>> import os; os.curdir
 '.'

I didn't have to ask to print out the '.'. It just did it.

Under the covers, one can see that this is implemented with the exec() function:

https://github.com/python/cpython/blob/800a35c623bbcdb5793c7d7a4974524286311479/Lib/code.py#L90

    try:
        exec(code, self.locals)
    except SystemExit:
        raise
    except:
        self.showtraceback()

The weird thing is that there is no explicit instruction there to output the result of the exec(). And yet we can see that it does output it.

We can see that this behaviour is very context specific like this:

$ echo "5" | python3 -c "import code; code.interact()"
Python 3.7.7 (default, Mar 10 2020, 15:43:03) 
(InteractiveConsole)
>>> 5
>>> 
now exiting InteractiveConsole...
enter code here

I assume that if I dig into the C code I will see that it is querying its context to see whether to output the value or not. But it wouldn't answer my main question, which is how to emulate this behaviour in an arbitrary context.

How can I can I execute and get the "pseudo-return value" from a Python string, regardless of whether the string represents an expression or a statement?

The Python compiler has a flag to keep track of whether Python is being run in interactive mode .

If this flag is set, when the compiler visits a statement node in the AST, it emits an extra PRINT_EXPR opcode .

The interpreter executes PRINT_EXPR by popping the result of the expression off the stack and passing it as an argument to sys.displayhook . The displayhook prints the repr of this value to stdout, unless the value is None. It also assigns the value to builtins._ .

(I guess the reason why the behavior is different when you pipe a command to Python is that then it is not in interactive mode.)

So as long as you are running Python in interactive mode, you can read the value of the _ builtin after running code with the exec builtin.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM