Ich möchte ein Python-Codebeispiel teilen, das etwas anderes tun sollte, wenn es im Terminal Python / IPython oder im IPython-Notizbuch ausgeführt wird.
Wie kann ich anhand meines Python-Codes überprüfen, ob er im IPython-Notizbuch ausgeführt wird?
Ich möchte ein Python-Codebeispiel teilen, das etwas anderes tun sollte, wenn es im Terminal Python / IPython oder im IPython-Notizbuch ausgeführt wird.
Wie kann ich anhand meines Python-Codes überprüfen, ob er im IPython-Notizbuch ausgeführt wird?
Antworten:
Die Frage ist, was Sie anders ausführen möchten.
Wir tun unser Bestes in IPython, um zu verhindern, dass der Kernel weiß, mit welcher Art von Frontend verbunden ist, und tatsächlich können Sie sogar einen Kernel gleichzeitig mit vielen verschiedenen Frontends verbinden. Selbst wenn Sie einen Blick auf die Art stderr/out
werfen können, um zu wissen, ob Sie sich in einem ZMQ-Kernel befinden oder nicht, garantiert dies Ihnen nicht, was Sie auf der anderen Seite haben. Sie könnten sogar überhaupt keine Frontends haben.
Sie sollten Ihren Code wahrscheinlich unabhängig vom Frontend schreiben. Wenn Sie jedoch verschiedene Dinge anzeigen möchten, können Sie das Rich-Display-System (Link an Version 4.x von IPython angeheftet) verwenden , um je nach Frontend verschiedene Dinge anzuzeigen Das Frontend wählt, nicht die Bibliothek.
\x1b[A
(nach oben), sodass verschachtelte Balken nicht gedruckt werden können . Kein Problem mit ipywidgets , wir können native Jupyter-Widgets verwenden, um Fortschrittsbalken anzuzeigen. Dann haben wir zwei verschiedene Möglichkeiten, einen Fortschrittsbalken anzuzeigen, und eine Anwendung möchte möglicherweise wissen, wie die Anzeigeumgebung aussieht, um den kompatiblen Balken anzupassen und zu drucken.
%matplotlib inline
wenn sie als Notebook fungiert, jedoch nicht in einem Terminal, da dies nicht erforderlich ist.
Folgendes hat für meine Bedürfnisse funktioniert:
get_ipython().__class__.__name__
Es kehrt 'TerminalInteractiveShell'
auf einem Terminal-IPython 'ZMQInteractiveShell'
auf Jupyter (Notebook UND qtconsole) zurück und schlägt NameError
auf einem normalen Python-Interpreter fehl ( ). Die Methode get_python()
scheint standardmäßig im globalen Namespace verfügbar zu sein, wenn IPython gestartet wird.
Wickeln Sie es in eine einfache Funktion:
def isnotebook():
try:
shell = get_ipython().__class__.__name__
if shell == 'ZMQInteractiveShell':
return True # Jupyter notebook or qtconsole
elif shell == 'TerminalInteractiveShell':
return False # Terminal running IPython
else:
return False # Other type (?)
except NameError:
return False # Probably standard Python interpreter
Das Obige wurde mit Python 3.5.2, IPython 5.1.0 und Jupyter 4.2.1 unter macOS 10.12 und Ubuntu 14.04.4 LTS getestet
jupyter console
, leider get_ipython()
gibt eine Instanz von ZMQInteractiveShell
auch
get_ipython().__class__.__module__ == "google.colab._shell"
test.py
dann from test import isnotebook; print(isnotebook())
in einem Jupyter-Notizbuch ausführe , wird sie gedruckt True
. (Getestet auf Notebook-Server-Versionen 5.2.1 und 6.0.1.)
Um zu überprüfen, ob Sie sich in einem Notizbuch befinden, was wichtig sein kann, z. B. wenn Sie bestimmen, welche Art von Fortschrittsbalken verwendet werden soll, hat dies für mich funktioniert:
def in_ipynb():
try:
cfg = get_ipython().config
if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
return True
else:
return False
except NameError:
return False
cfg['IPKernelApp']['parent_appname']
befindet sich ein IPython.config.loader.LazyConfigValue
, der nicht True
mit"iypthon-notebook"
IPython.kernel.zmq.zmqshell.ZMQInteractiveShell
Instanz in ipynb (Jupyter) und eine IPython.terminal.interactiveshell.TerminalInteractiveShell
in einem Terminal REPL zurück, falls Sie zwischen Notebooks und Terminal / Konsolen unterscheiden müssen (was sich auf das Plotten auswirkt).
try
Blocks ersetzen durch:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
shell='PyDevTerminalInteractiveShell'
beim Überprüfen des Klassennamens angezeigt.
Mit dem folgenden Snippet [1] können Sie überprüfen, ob sich Python im interaktiven Modus befindet :
def is_interactive():
import __main__ as main
return not hasattr(main, '__file__')
Ich habe diese Methode als sehr nützlich empfunden, da ich viel Prototyping im Notebook mache. Zu Testzwecken verwende ich Standardparameter. Ansonsten lese ich die Parameter aus sys.argv
.
from sys import argv
if is_interactive():
params = [<list of default parameters>]
else:
params = argv[1:]
Nach der Implementierung von autonotebook
können Sie anhand des folgenden Codes feststellen, ob Sie sich in einem Notizbuch befinden.
def in_notebook():
try:
from IPython import get_ipython
if 'IPKernelApp' not in get_ipython().config: # pragma: no cover
return False
except ImportError:
return False
return True
is_interactive()
unterscheidet nicht zwischen Notebook und Konsole.
%run
von ipython ausgibt, ist nicht interaktiv. Man könnte argumentieren, dass es so sein sollte, aber es ist immer noch ein Gotcha.
is_interactive
) scheint mir für die Frage grundsätzlich irrelevant zu sein. Es ist auch von zweifelhafter Korrektheit; Wie @marscher betont, zählt alles, was ausgeführt wird, python -c
als "interaktiv", obwohl dies nicht der Fall ist. Ich möchte es nicht selbst tun, da es nicht meine Antwort ist, aber ich denke, dies würde durch einfaches Löschen der gesamten ersten Hälfte der Antwort verbessert.
Kürzlich bin ich auf einen Fehler im Jupyter-Notizbuch gestoßen, der eine Problemumgehung erfordert, und ich wollte dies tun, ohne die Funktionalität in anderen Shells zu verlieren. Ich habe festgestellt, dass die Lösung von keflavich in diesem Fall nicht funktioniert, da get_ipython()
sie nur direkt vom Notebook und nicht von importierten Modulen verfügbar ist. So habe ich einen Weg gefunden, anhand meines Moduls zu erkennen, ob es von einem Jupyter-Notebook importiert und verwendet wird oder nicht:
import sys
def in_notebook():
"""
Returns ``True`` if the module is running in IPython kernel,
``False`` if in IPython shell or other Python shell.
"""
return 'ipykernel' in sys.modules
# later I found out this:
def ipython_info():
ip = False
if 'ipykernel' in sys.modules:
ip = 'notebook'
elif 'IPython' in sys.modules:
ip = 'terminal'
return ip
Kommentare sind willkommen, wenn dies robust genug ist.
Auf ähnliche Weise können Sie auch Informationen zum Client und zur IPython-Version abrufen:
import sys
if 'ipykernel' in sys.modules:
ip = sys.modules['ipykernel']
ip_version = ip.version_info
ip_client = ip.write_connection_file.__module__.split('.')[0]
# and this might be useful too:
ip_version = IPython.utils.sysinfo.get_sys_info()['ipython_version']
'Ipython' in sys.modules
ausgewertet False
. Vielleicht meinst du 'IPython' in sys.modules
? Dies ist True
in meiner Jupyter-Umgebung. Das sys.modules
Wörterbuch enthält auch nicht den 'ipykernel'
Schlüssel - wenn es in einem Notizbuch ausgeführt wird.
Getestet auf Python 3.7.3
CPython-Implementierungen haben den Namen __builtins__
übrigens als Teil ihrer Globals verfügbar. kann von der Funktion globals () abgerufen werden.
Wenn ein Skript in einer Ipython-Umgebung ausgeführt wird, __IPYTHON__
sollte dies ein Attribut von sein __builtins__
.
Der folgende Code wird daher zurückgegeben, True
wenn er unter Ipython ausgeführt wird oder wenn er angezeigt wirdFalse
hasattr(__builtins__,'__IPYTHON__')
Im Folgenden werden die Fälle von https://stackoverflow.com/a/50234148/1491619 erfasst, ohne dass die Ausgabe von analysiert werden mussps
def pythonshell():
"""Determine python shell
pythonshell() returns
'shell' (started python on command line using "python")
'ipython' (started ipython on command line using "ipython")
'ipython-notebook' (e.g., running in Spyder or started with "ipython qtconsole")
'jupyter-notebook' (running in a Jupyter notebook)
See also https://stackoverflow.com/a/37661854
"""
import os
env = os.environ
shell = 'shell'
program = os.path.basename(env['_'])
if 'jupyter-notebook' in program:
shell = 'jupyter-notebook'
elif 'JPY_PARENT_PID' in env or 'ipython' in program:
shell = 'ipython'
if 'JPY_PARENT_PID' in env:
shell = 'ipython-notebook'
return shell
jupyter
ob es ein jupyter console
, jupyter qtconsole
oder jupyter notebook
.
Ich würde empfehlen, das Erkennen eines bestimmten Frontends zu vermeiden, da es zu viele davon gibt . Stattdessen können Sie einfach testen, ob Sie in einer iPython-Umgebung ausgeführt werden:
def is_running_from_ipython():
from IPython import get_ipython
return get_ipython() is not None
Oben wird zurückgegeben, False
wenn Sie über die running_from_ipython
übliche Python-Befehlszeile aufrufen . Wenn Sie es über Jupyter Notebook, JupyterHub, iPython Shell, Google Colab usw. aufrufen, wird es zurückgegeben True
.
get_ipython()
kehrt es zurück <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>
.
get_ipython() is not None
zurück True
.
Sie müssen lediglich diese beiden Zellen am Anfang Ihres Notizbuchs platzieren:
Zelle 1: (markiert als "Code"):
is_notebook = True
Zelle 2: (markiert als "Raw NBConvert"):
is_notebook = False
Die erste Zelle wird immer ausgeführt, die zweite Zelle wird jedoch nur ausgeführt, wenn Sie das Notizbuch als Python-Skript exportieren.
Später können Sie überprüfen:
if is_notebook:
notebook_code()
else:
script_code()
Hoffe das hilft.
Wie wäre es mit so etwas:
import sys
inJupyter = sys.argv[-1].endswith('json')
print(inJupyter);
Soweit ich weiß, hat Here 3 Arten von Ipython verwendet ipykernel
ipython qtconsole
(kurz "qtipython")Verwendung 'spyder' in sys.modules
kann Spyder unterscheiden
aber für qtipython und jn ist die Ursache schwer zu unterscheiden
Sie haben die sys.modules
gleiche IPython-Konfiguration:get_ipython().config
Ich finde einen Unterschied zwischen qtipython und jn:
Beim ersten Ausführen os.getpid()
in der IPython-Shell wird die PID-Nummer abgerufen
dann renne ps -ef|grep [pid number]
meine qtipython pid ist 8699
yanglei 8699 8693 4 20:31 ? 00:00:01 /home/yanglei/miniconda2/envs/py3/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-8693.json
meine jn pid ist 8832
yanglei 8832 9788 13 20:32 ? 00:00:01 /home/yanglei/miniconda2/bin/python -m ipykernel_launcher -f /run/user/1000/jupyter/kernel-ccb962ec-3cd3-4008-a4b7-805a79576b1b.json
Der Unterschied zwischen qtipython und jn ist der json-Name des ipython. Der json-Name von jn ist länger als der von qtipython
Daher können wir alle Python-Umgebungen automatisch anhand des folgenden Codes erkennen:
import sys,os
def jupyterNotebookOrQtConsole():
env = 'Unknow'
cmd = 'ps -ef'
try:
with os.popen(cmd) as stream:
if not py2:
stream = stream._stream
s = stream.read()
pid = os.getpid()
ls = list(filter(lambda l:'jupyter' in l and str(pid) in l.split(' '), s.split('\n')))
if len(ls) == 1:
l = ls[0]
import re
pa = re.compile(r'kernel-([-a-z0-9]*)\.json')
rs = pa.findall(l)
if len(rs):
r = rs[0]
if len(r)<12:
env = 'qtipython'
else :
env = 'jn'
return env
except:
return env
pyv = sys.version_info.major
py3 = (pyv == 3)
py2 = (pyv == 2)
class pyi():
'''
python info
plt : Bool
mean plt avaliable
env :
belong [cmd, cmdipython, qtipython, spyder, jn]
'''
pid = os.getpid()
gui = 'ipykernel' in sys.modules
cmdipython = 'IPython' in sys.modules and not gui
ipython = cmdipython or gui
spyder = 'spyder' in sys.modules
if gui:
env = 'spyder' if spyder else jupyterNotebookOrQtConsole()
else:
env = 'cmdipython' if ipython else 'cmd'
cmd = not ipython
qtipython = env == 'qtipython'
jn = env == 'jn'
plt = gui or 'DISPLAY' in os.environ
print('Python Envronment is %s'%pyi.env)
Der Quellcode ist hier: Erkennung Python-Umgebung, besonders unterscheiden Spyder, Jupyter Notebook, Qtconsole.py
Ich verwende Django Shell Plus, um IPython zu starten, und wollte "In Notebook ausführen" als Django-Einstellungswert verfügbar machen. get_ipython()
ist beim Laden von Einstellungen nicht verfügbar, daher verwende ich diese (die nicht kugelsicher ist, aber für die lokalen Entwicklungsumgebungen, in denen sie verwendet wird, gut genug ist):
import sys
if '--notebook' in sys.argv:
ENVIRONMENT = "notebook"
else:
ENVIRONMENT = "dev"
Angenommen, Sie haben die Kontrolle über das Jupyter-Notizbuch, könnten Sie:
Legen Sie einen Umgebungswert in einer Zelle fest, der diesen Wert als Flag in Ihrem Code verwendet . Fügen Sie einen eindeutigen Kommentar in diese Zelle ein (oder in alle Zellen, die Sie ausschließen möchten).
# exclude_from_export
% set_env is_jupyter = 1
Exportieren Sie das Notizbuch als Python-Skript, um es in einem anderen Kontext zu verwenden. Der Export würde die kommentierten Zellen und anschließend den Code ausschließen, der den Umgebungswert festlegt. Hinweis: Ersetzen Sie your_notebook.ipynb durch den Namen Ihrer tatsächlichen Notebook-Datei.
jupyter nbconvert --to script --RegexRemovePreprocessor.patterns = "['^ # exclude_from_export']" your_notebook.ipynb
Dadurch wird eine Datei generiert, für die das Jupyter-Umgebungsflag nicht gesetzt ist. Dies ermöglicht Code, der es zur deterministischen Ausführung verwendet.