70

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

I've looked at tell whether python is in -i mode and tried the code there, however, that function only returns true if Python has been invoked with the -i flag and not when the command used to invoke interactive mode is python with no arguments.

What I mean is something like this:

if __name__=="__main__":
    #do stuff
elif __pythonIsInteractive__:
    #do other stuff
else:
    exit()
Community
  • 1
  • 1
Chinmay Kanchi
  • 62,729
  • 22
  • 87
  • 114
  • Consider using the `logging` module for logging in libraries, so users can control it with a shared configuration. – Bachsau Jun 17 '19 at 11:46

7 Answers7

70

__main__.__file__ doesn't exist in the interactive interpreter:

import __main__ as main
print hasattr(main, '__file__')

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

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 5
    This is also the case in, for example, py2exe executables. – fmark Jul 13 '10 at 13:46
  • 6
    Unfortunately this doesn't work inside an embedded shell. I.e. a shell started with IPython.embed() – titusjan Oct 30 '15 at 11:27
  • 9
    `bool(getattr(sys, 'ps1', sys.flags.interactive))`, py2.6+ – Mr. B Dec 09 '17 at 23:15
  • 1
    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. – photon.engine Jul 08 '20 at 05:27
  • This is the only answer that worked for `ptpython` interactive session started via `python -m ptpython`. – JamesThomasMoon Sep 11 '21 at 01:55
50

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

pyjamas
  • 4,608
  • 5
  • 38
  • 70
29

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

Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
  • @Keith seems to work fine for me in iPython 3.2.1 REPL using python 2.7.9 – hobs Oct 09 '15 at 21:43
  • 2
    Agreed, I just checked in 4.0 and it works there as well. May have been an issue with older versions of IPython. – Keith Hughitt Oct 10 '15 at 11:28
  • Seems to me that `sys.ps1` and `sys.ps2` are defined even when iPython is run *not* in interactive mode. – Jasha Mar 01 '20 at 06:40
17

Use sys.flags:

if sys.flags.interactive:
    #interactive
else:
    #not interactive 
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Pych
  • 241
  • 2
  • 3
  • 14
    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. – the wolf Jun 12 '12 at 15:59
  • 10
    `bool(getattr(sys, 'ps1', sys.flags.interactive))` – Mr. B Dec 09 '17 at 23:13
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.

wersimmon
  • 2,809
  • 3
  • 22
  • 35
  • 1
    Uh oh. Direct violation of the Zen of Python, then :) – Tim Pietzcker Mar 01 '10 at 14:33
  • 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... – Chinmay Kanchi Mar 01 '10 at 14:59
  • 5
    This may be problematic for other interpreters, however. For example, when using IPython, sys.argv = ['/usr/bin/ipython'] – Keith Hughitt Aug 03 '11 at 13:12
1

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'
jdines
  • 19
  • 2
  • 1
    `if sys.ps1: interpreter = True` => `interpreter = sys.ps1` or `interpreter = bool(sys.ps1)`. – Cristian Ciupitu Jul 13 '14 at 16:25
  • @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. – jdines Jul 13 '14 at 18:02
  • Did I recommend removing the `try ... except` statement? I only recommended replacing an `if` with a plain assignment. – Cristian Ciupitu Jul 13 '14 at 18:10
  • @CristianCiupitu: You made no such recommendation. Apparently you thought that the => communicated a whole lot more than it actually does. Of course, once one understands what you meant to say rather than what you said, your solution is longer and more compute intensive, but whatever floats your boat I suppose. – jdines Jul 13 '14 at 18:15
  • 1
    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`. – Cristian Ciupitu Jul 13 '14 at 18:21
  • I mistook the last "or" as a Python statement rather than an English word, so as you say "my bad" on that. Now that I see that, your first proposal will assign ">>> " to sys.ps1 thereby causing a cast every time you use it, and also introducing an inconsistency where the type of "interpreter" is different depending upon runtime mode. On my system the pyc file for my solution is 3 bytes smaller than your second solution: You can try it yourself to verify, obviously. – jdines Jul 13 '14 at 19:40
  • You're right about that inconsistency, that's why I also proposed a second variant. I have python-2.7.5-13.fc20.x86_64 and the corresponding **pyc** is indeed bigger with 5 bytes for the `bool` variant. But if I also change the `except` code to `interpreter = bool(sys.flags.interactive)`, the file is smaller with 27 bytes :-D – Cristian Ciupitu Jul 13 '14 at 20:28
  • 2
    NECROMANCY!: `bool(getattr(sys, 'ps1', sys.flags.interactive))` – Mr. B Dec 09 '17 at 23:11
-4

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

JAB
  • 20,783
  • 6
  • 71
  • 80