Ho qualche esempio di codice Python che vorrei condividere che dovrebbe fare qualcosa di diverso se eseguito nel terminale Python / IPython o nel notebook IPython.
Come posso controllare dal mio codice Python se è in esecuzione nel notebook IPython?
Ho qualche esempio di codice Python che vorrei condividere che dovrebbe fare qualcosa di diverso se eseguito nel terminale Python / IPython o nel notebook IPython.
Come posso controllare dal mio codice Python se è in esecuzione nel notebook IPython?
Risposte:
La domanda è cosa vuoi eseguire in modo diverso.
Facciamo del nostro meglio in IPython per impedire al kernel di sapere a quale tipo di frontend è connesso, e in realtà puoi persino avere un kernel connesso a molti frontend diversi contemporaneamente. Anche se puoi dare un'occhiata al tipo di stderr/outper sapere se sei in un kernel ZMQ o no, non ti garantisce quello che hai dall'altra parte. Potresti anche non avere alcun frontend.
Probabilmente dovresti scrivere il tuo codice in modo indipendente dal frontend, ma se vuoi visualizzare cose diverse, puoi usare il ricco sistema di visualizzazione (collegamento bloccato alla versione 4.x di IPython) per visualizzare cose diverse a seconda del frontend, ma il frontend sceglierà, non la libreria.
\x1b[A(sposta su), quindi non è possibile stampare barre nidificate . Nessun problema con ipywidgets , possiamo utilizzare widget nativi di Jupyter per visualizzare le barre di avanzamento. Ma poi abbiamo due modi diversi per visualizzare una barra di avanzamento e un'applicazione potrebbe voler sapere qual è l'ambiente di visualizzazione per adattare e stampare la barra compatibile.
%matplotlib inlinequando agisce come un notebook, ma non in un terminale, poiché non è necessario.
Quanto segue ha funzionato per le mie esigenze:
get_ipython().__class__.__name__
Ritorna 'TerminalInteractiveShell'su un terminale IPython, 'ZMQInteractiveShell'su Jupyter (notebook AND qtconsole) e fail ( NameError) su un normale interprete Python. Il metodo get_python()sembra essere disponibile nello spazio dei nomi globale per impostazione predefinita quando viene avviato IPython.
Avvolgendolo in una semplice funzione:
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
Quanto sopra è stato testato con Python 3.5.2, IPython 5.1.0 e Jupyter 4.2.1 su macOS 10.12 e Ubuntu 14.04.4 LTS
jupyter console, purtroppo get_ipython()restituisce un'istanza ZMQInteractiveShellanche
get_ipython().__class__.__module__ == "google.colab._shell"
test.pypoi from test import isnotebook; print(isnotebook())eseguo in un notebook Jupyter, viene stampata True. (Testato sulle versioni server Notebook 5.2.1 e 6.0.1.)
Per verificare se sei in un notebook, che può essere importante ad esempio quando si determina quale tipo di barra di avanzamento utilizzare, questo ha funzionato per me:
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']è una IPython.config.loader.LazyConfigValueche non si confronta con Truecon"iypthon-notebook"
IPython.kernel.zmq.zmqshell.ZMQInteractiveShellun'istanza in ipynb (Jupyter) e una IPython.terminal.interactiveshell.TerminalInteractiveShellin un terminale REPL, nel caso in cui sia necessario distinguere tra notebook e terminale / console (che influisce sulla stampa).
tryblocco con:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
shell='PyDevTerminalInteractiveShell'ispezione del nome della classe.
Puoi verificare se Python è in modalità interattiva con il seguente frammento [1] :
def is_interactive():
import __main__ as main
return not hasattr(main, '__file__')
Ho trovato questo metodo molto utile perché faccio molti prototipi nel notebook. A scopo di test, utilizzo i parametri predefiniti. Altrimenti leggo i parametri da sys.argv.
from sys import argv
if is_interactive():
params = [<list of default parameters>]
else:
params = argv[1:]
Dopo l'implementazione di autonotebook, è possibile stabilire se si è in un notebook utilizzando il codice seguente.
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()non distingue tra notebook e console.
%runda ipython non è interattivo. Potresti obiettare che dovrebbe essere, ma è ancora un trucco.
is_interactive) mi sembra sostanzialmente irrilevante per la domanda. È anche di dubbia correttezza; come fa notare @marscher, conta qualsiasi cosa eseguita utilizzando python -ccome in modalità "interattiva" anche se questo non è vero. Non voglio farlo da solo poiché non è la mia risposta, ma penso che sarebbe migliorato semplicemente eliminando l'intera prima metà della risposta.
Recentemente ho riscontrato un bug nel notebook Jupyter che necessita di una soluzione alternativa e volevo farlo senza perdere funzionalità in altre shell. Mi sono reso conto che la soluzione di keflavich non funziona in questo caso, perché get_ipython()è disponibile solo direttamente dal notebook e non dai moduli importati. Quindi ho trovato un modo per rilevare dal mio modulo se è importato e utilizzato da un notebook Jupyter o meno:
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
I commenti sono apprezzati se questo è abbastanza solido.
In modo simile è possibile ottenere alcune informazioni sul client e anche sulla versione di IPython:
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.modulesvaluta False. Forse vuoi dire 'IPython' in sys.modules? Questo è Truenel mio ambiente Jupyter. Il sys.modulesdizionario inoltre non include la 'ipykernel'chiave, quando si esegue in un notebook.
Testato per python 3.7.3
Le implementazioni di CPython hanno il nome __builtins__disponibile come parte delle loro globali che btw. può essere recuperato dalla funzione globals ().
Se uno script è in esecuzione in un ambiente Ipython, __IPYTHON__dovrebbe essere un attributo di __builtins__.
Il codice seguente quindi restituisce Truese eseguito in Ipython oppure dàFalse
hasattr(__builtins__,'__IPYTHON__')
Quanto segue acquisisce i casi di https://stackoverflow.com/a/50234148/1491619 senza la necessità di analizzare l'output dips
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
jupyterche si tratti di una jupyter console, jupyter qtconsoleo jupyter notebook.
Consiglierei di evitare di rilevare frontend specifici perché ce ne sono troppi . Invece puoi semplicemente testare se stai eseguendo dall'ambiente iPython:
def is_running_from_ipython():
from IPython import get_ipython
return get_ipython() is not None
Sopra tornerà Falsese stai invocando running_from_ipythondalla normale riga di comando di Python. Quando lo richiami da Jupyter Notebook, JupyterHub, iPython shell, Google Colab ecc True., Tornerà .
get_ipython()restituisce <ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>.
get_ipython() is not Noneindietro True.
Tutto quello che devi fare è posizionare queste due celle all'inizio del tuo quaderno:
Cella 1: (contrassegnata come "codice"):
is_notebook = True
Cella 2: (contrassegnata come "Raw NBConvert"):
is_notebook = False
La prima cella verrà sempre eseguita, ma la seconda verrà eseguita solo quando esporti il notebook come script Python.
Successivamente, puoi controllare:
if is_notebook:
notebook_code()
else:
script_code()
Spero che sia di aiuto.
Che ne dici di qualcosa del genere:
import sys
inJupyter = sys.argv[-1].endswith('json')
print(inJupyter);
Per quanto ne so, qui ha 3 tipi di ipython utilizzati ipykernel
ipython qtconsole ("qtipython" in breve)l'uso 'spyder' in sys.modulespuò distinguere Spyder
ma per qtipython e jn è difficile distinguere la causa
hanno la stessa sys.modulese stessa configurazione IPython:get_ipython().config
Trovo una differenza tra qtipython e jn:
prima esecuzione os.getpid()nella shell IPython ottieni il numero pid
quindi corri ps -ef|grep [pid number]
il mio pid qtipython è 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
il mio jn pid è 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
il diverso di qtipython e jn è il nome json di ipython, il nome json di jn è più lungo di quello di qtipython
quindi, possiamo rilevare automaticamente tutto l'ambiente Python seguendo il codice:
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)
il codice sorgente è qui: Detection Python Environment, Soprattutto distinguere Spyder, Jupyter notebook, Qtconsole.py
Sto usando Django Shell Plus per avviare IPython e volevo rendere disponibile "running in notebook" come valore delle impostazioni Django. get_ipython()non è disponibile durante il caricamento delle impostazioni, quindi lo uso (che non è a prova di proiettile, ma abbastanza buono per gli ambienti di sviluppo locale in cui è utilizzato):
import sys
if '--notebook' in sys.argv:
ENVIRONMENT = "notebook"
else:
ENVIRONMENT = "dev"
Supponendo che tu abbia il controllo del Jupyter Notebook potresti:
impostare un valore di ambiente in una cella che lo utilizza come flag nel codice . Inserisci un commento univoco in quella cella (o in tutte le celle che desideri escludere)
# exclude_from_export
% set_env is_jupyter = 1
Esporta il notebook come script Python da utilizzare in un contesto diverso. L'esportazione escluderebbe le celle commentate e successivamente il codice che imposta il valore dell'ambiente. Nota: sostituisci your_notebook.ipynb con il nome del tuo file notebook effettivo.
jupyter nbconvert --to script --RegexRemovePreprocessor.patterns = "['^ # exclude_from_export']" tuo_notebook.ipynb
Questo genererà un file che non avrà il flag di ambiente jupyter impostato, consentendo l'esecuzione deterministica del codice che lo utilizza.