78

In a Python script, is there any way to tell if the interpreter is running in interactive mode? This would be useful so that, for instance, when you run an interactive Python session and import a module, different code can be executed.

What I mean is something like this:

if __name__ == "__main__":
    # do stuff
elif __pythonIsInteractive__:
    # do other stuff
else:
    exit()
0

7 Answers 7

70

Python <= 3.12

__main__.__file__ doesn't exist in the interactive interpreter for Python versions <= 3.12:

import __main__
print(hasattr(__main__, "__file__"))

This also goes for code run via python -c, but not python -m.

Sign up to request clarification or add additional context in comments.

6 Comments

This is also the case in, for example, py2exe executables.
Unfortunately this doesn't work inside an embedded shell. I.e. a shell started with IPython.embed()
bool(getattr(sys, 'ps1', sys.flags.interactive)), py2.6+
So far none of the solutions seems to be able to detect PYTHONSTARTUP=script.py python3. The expression 'readline' in sys.modules can, as well as python3 -i script.py and python3 -ic 'import script' (tested with Python 3.8.2 on Ubuntu focal), but it's highly non-portable.
This is the only answer that worked for ptpython interactive session started via python -m ptpython.
|
69

I compared all the methods I found and made a table of results. The best one seems to be this:

hasattr(sys, 'ps1')

enter image description here

If anyone has other scenarios that might differ, comment and I'll add it

10 Comments

Hey thank you for doing the hard work, would you be able to check Windows vs Linux vs Mac?
hasattr(sys, 'ps1') returns False in PyCharm 2022.1.4 (CE) console on Windows 11
I i forgot to mention that the interpreter is Python 3.10.6
@ultrafunkamsterdam Because hasattr(sys, 'ps1') matched the values in the first row labelled "Expected". The problem with sys.__stdout__.isatty was that it returned True where it shouldn't, like when running a Python file in a shell.
I think you should mention what Python version your table represents. Because the results depend on Python version (for example, __main__.__file__ is there in Python 3.13 but missing in Python 3.12).
|
32

sys.ps1 and sys.ps2 are only defined in interactive mode.

3 Comments

@Keith seems to work fine for me in iPython 3.2.1 REPL using python 2.7.9
Agreed, I just checked in 4.0 and it works there as well. May have been an issue with older versions of IPython.
Seems to me that sys.ps1 and sys.ps2 are defined even when iPython is run not in interactive mode.
23

Use sys.flags:

if sys.flags.interactive:
    #interactive
else:
    #not interactive 

2 Comments

This only checks for command line argument python -i and is not a test of being in the Python interactive mode by typing python alone.
bool(getattr(sys, 'ps1', sys.flags.interactive))
7

From TFM: If no interface option is given, -i is implied, sys.argv[0] is an empty string ("") and the current directory will be added to the start of sys.path.

If the user invoked the interpreter with python and no arguments, as you mentioned, you could test this with if sys.argv[0] == ''. This also returns true if started with python -i, but according to the docs, they're functionally the same.

3 Comments

Uh oh. Direct violation of the Zen of Python, then :)
Heh... Though I think @echoback's version is the only obvious(ish) one. I didn't accept this simply because in C et al., it is theoretically possible that argv[0] is NULL or an empty string and I don't really feel like debugging any potential errors caused by that...
This may be problematic for other interpreters, however. For example, when using IPython, sys.argv = ['/usr/bin/ipython']
0

The following works both with and without the -i switch:

#!/usr/bin/python
import sys
# Set the interpreter bool
try:
    if sys.ps1: interpreter = True
except AttributeError:
    interpreter = False
    if sys.flags.interactive: interpreter = True

# Use the interpreter bool
if interpreter: print 'We are in the Interpreter'
else: print 'We are running from the command line'

8 Comments

if sys.ps1: interpreter = True => interpreter = sys.ps1 or interpreter = bool(sys.ps1).
@CristianCiupitu: You might want to actually test your code before you post it. Even if it was valid Python it would throw an AttribeError exception when run from the command line.
Did I recommend removing the try ... except statement? I only recommended replacing an if with a plain assignment.
My bad for being elliptic, but I fail to understand how 27 characters are longer than 30 or why is it more compute intensive when if also needs the boolean value of sys.ps1.
NECROMANCY!: bool(getattr(sys, 'ps1', sys.flags.interactive))
|
-6

Here's something that would work. Put the following code snippet in a file, and assign the path to that file to the PYTHONSTARTUP environment variable.

__pythonIsInteractive__ = None

And then you can use

if __name__=="__main__":
    #do stuff
elif '__pythonIsInteractive__' in globals():
    #do other stuff
else:
    exit()

http://docs.python.org/tutorial/interpreter.html#the-interactive-startup-file

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.