❯ ./python -c 'import sys; sys.version_info'
❯ ./python -pc 'import sys; sys.version_info'
sys.version_info(major=3, minor=15, micro=0, releaselevel='alpha', serial=0)
❯ ./python --help | rg -m 1 -- '-p'
-p : print the result of the program passed in as string (use with -c)
It eliminates the need to use print() for most common use cases of -c by tweaking the internal compilation mode to "single", the same one that is used by the REPL to display results of prompts (via sys.displayhook) which may consist of multiple statements.
The interface and the explanation may (and probably should :-)) be a little different, we could add an env var etc.
For now, I found adding a new flag the easiest.
A PoC without tests is here: GitHub - bswck/cpython at b/print-prog-result-option
Small backward compatibility note here: if it’s a good idea, it must be an extra option.
FWIW, most workflows that have a print or other void function at the end wouldn’t break, because displayhook() avoids writing None, but some that don’t and still write to stdout could result in mixed output.
-0 from me. It’s convenient, but pre-importing sys (or math, or random, …) would also be useful. There’s too much potential for scope creep. And it’s not that hard to write a helper:
I’ve seen lots and lots of times people writing prints in python -c, so I thought: why not support it out of the box in Python?
I must admit that I’ve seen pypyp before. I agree that it’s much more powerful and well-suited for perhaps what this idea only partially addresses, as you’ve accurately shown. I didn’t use pypyp because I had thought I would need to install it separately for every Python – but now I have the idea that I’ll just make a Linux-only fork of pypyp installed globally that would execv itself in the right Python.
Given that single mode prints every expression statement, and implementing this feature without that flaw would be unobvious (we would need to deconstruct the input just like the REPL does), I think I’m going to back off from this idea. I’ll just use prints / pypyp + execv.
Not every idea is a good idea, and this one is “meh” after reconsideration. Good insights as always, thanks a lot everybody!
I can appreciate this viewpoint. But equally, I’m tired of every “nice to have” convenience being proposed as yet another language or interpreter feature.
Another option is to make this a stdlib module py -m utils.eval sys.version_info. But that’s hard to get agreement on, because a significant group of the core devs prefers to have a smaller stdlib, rather than a large “batteries included” one. Personally, I think it’s silly to even consider an interpreter option when a stdlib module would work just fine - adding options because of politics around the role of the stdlib is the wrong approach. We should decide if the functionality is worthwhile and then decide how to implement it. Personally, I think that if this is worth having[1], a stdlib module is just fine. If you disagree, what exactly does that say about Python as a language for implementing utility tools in, that you’re willing to argue for a C implementation in the core over a pure Python library module?
That leaves us with “write your own, or use a 3rd party package”. I appreciate that using packages from PyPI can be harder than we’d like it to be, especially for utility applications and scripts, but again that doesn’t mean we should bloat the core - instead we should fix the real problem, which is that distributing 3rd party utilities written in Python isn’t easy enough.
For now, I find it hard to see why:
uvx pypyp
Unpacking the pypyp wheel and putting the single pyp.py file somewhere on your PATH
Writing a wrapper script that invokes compile and exec as we’ve discussed here
are all so difficult that building something into the interpreter is the only viable option.
Personally, I just use python -c "import sys; print(sys.version_info)". I don’t think the proposed functionality is enough of a saving in any case. I’d probably still use the explicit version over a -p option, if it was added, if only because at this point it’s in my muscle memory and the benefit is too small to be worth retraining.
I don’t understand how that would help. What do you have in PYTHONSTARTUP that you couldn’t add to your script if the script needed it?
And it doesn’t seem helpful for the OP’s requirement, as that was just to print the last expression - not something PYTHONSTARTUP can do. Of course, if you’re thinking about automatically importing things like sys, then we’re already extending the scope of the original request, and that’s precisely why I expressed reservations that the feature was a magnet for scope creep
Having said that, as a general point I would be in favour of proposals that offered more flexible extensions to the basic command line experience. The key here is flexible - rather than providing one very specific behaviour like the proposed -p, instead provide a means of invoking your own behaviours, that you can develop as scripts. That’s what the -m flag offers, but it’s limited to running installed packages. I’d quite like an option that tells the interpreter to scan PATH for the script when invoking py script.py - it’s unnecessary on Unix (where you can just use a shebang), but it would be helpful on Windows, where “executable extensions” are a poor substitute. I’m not sure it would get support, though - we’re not typically in the business of patching over poor OS functionality.
But in any case, we’d just be back round to your reluctance to rely on 3rd party code or your own utilities - such a feature would still require you to find or write a script that did the “print the last expression” functionality. I don’t know how we can resolve the problem where the requested functionality only requires a short “convenience” script, but users aren’t willing to write or locate such scripts, instead expecting the interpreter to cover everything they need directly.
Well, it would not exactly address OP’s issue, but personally, I am quite happy with 'sys.version > p'.
Maybe not as ideal, but given that this benefit would be just a side effect of more general thing, this is good enough for me.
Yes.
Yes.
Additionally, one specific use case that I have is that I have startup script, which is quite extensive.
I often do initial scribblings in REPL. When I start writing functions, then I move things to a file and start running stuff via python file.py. When that gets big enough, I move it to library, etc…
The point is that transition from REPL to script can take a bit more than desirable. Nothing tragic, but given the amount of code that has been written up to that point, the percentage of imports that I need to do is noticeable.
But yeah, this would be a general thing - REPL launches PYTHONSTARTUP. Have an option to load it when doing python file.py or python -c '...'.
Thanks. I understand your use case a lot better now. But presumably, at some point in the life of a script, unless it’s never going to be anything than a personal utility, you’ll need to decouple it from its dependency on your personal startup code? So a flag such as you propose will delay that point, but not remove it completely.
As an alternative to needing language support, you could add the following boilerplate to the top of your script to execute your PYTHONSTARTUP file. IMO, that’s probably a better approach (explicit is better than implicit…):
I’m not sure that coupling scripts tightly to the user’s local setup (via PYTHONSTARTUP) is something that would be supported as a language feature - it’s certainly not something I’d personally use. But if you feel it would be useful, by all means make a proposal (in a different thread - we’ve already highjacked this thread enough!!!)
It depends. In old REPL - both expressions are printed, e.g.:
Python 3.12.11 (tags/v3.12.11:55fee9cf21, Aug 7 2025, 15:54:22) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1;2;3
1
2
3
Not sure if this is a bug or feature, I filled issue.
I am opposed to special-case replacing the 7 chars print(...), which I must remember anyway, with yet another startup option. There are already too many of the latter for me to keep track of.
I’m open to making changes to the way python -m runpy -c ... works (I think that’s currently just an error, as I don’t recall ever making it do anything else)