我想分享一些Python代码示例,如果在终端Python / IPython或IPython笔记本中执行,则应该做一些不同的事情。
如何检查我的Python代码是否在IPython笔记本中运行?
Answers:
问题是您想以不同的方式执行什么。
我们在IPython中尽力防止内核知道连接到哪种前端,实际上,您甚至可以同时将内核连接到许多不同的前端。即使您可以窥视一下stderr/out
是否知道您是否在ZMQ内核中,它也不能保证您在另一端拥有什么。您甚至根本没有前端。
您可能应该以独立于前端的方式编写代码,但是如果要显示不同的内容,则可以使用丰富的显示系统(固定到IPython版本4.x的链接)根据前端显示不同的内容,但是前端会选择,而不是库。
\x1b[A
(向上移动),因此无法打印嵌套的条形图。ipywidgets没问题,我们可以使用本机Jupyter小部件显示进度条。但是然后我们有两种不同的方式来显示进度条,并且应用程序可能想知道什么显示环境才能适应和打印兼容的条。
%matplotlib inline
在充当笔记本时始终运行,但不在终端中运行,因为这不是必需的。
以下满足我的需求:
get_ipython().__class__.__name__
它在Jupyter'TerminalInteractiveShell'
上的终端IPython 'ZMQInteractiveShell'
(笔记本和qtconsole)上返回,并NameError
在常规Python解释器上失败()。get_python()
启动IPython时,默认情况下该方法似乎在全局名称空间中可用。
将其包装成一个简单的函数:
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
以上已在macOS 10.12和Ubuntu 14.04.4 LTS上使用Python 3.5.2,IPython 5.1.0和Jupyter 4.2.1进行了测试
jupyter console
,不幸的是get_ipython()
返回的实例ZMQInteractiveShell
也
get_ipython().__class__.__module__ == "google.colab._shell"
test.py
然后from test import isnotebook; print(isnotebook())
在Jupyter Notebook中运行,它将打印True
。(在笔记本服务器版本5.2.1和6.0.1上进行了测试。)
要检查您是否在笔记本中,这可能很重要,例如,在确定要使用哪种进度条时,这对我有用:
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']
是IPython.config.loader.LazyConfigValue
,它True
与"iypthon-notebook"
IPython.kernel.zmq.zmqshell.ZMQInteractiveShell
在ipynb(Jupyter)中返回一个实例,并IPython.terminal.interactiveshell.TerminalInteractiveShell
在终端REPL中返回一个实例,以防您需要区分笔记本和终端/控制台(这会影响绘图)。
try
块的内部替换为:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
shell='PyDevTerminalInteractiveShell'
在检查类名时也会得到。
您可以使用以下代码段[1]检查python是否处于交互模式:
def is_interactive():
import __main__ as main
return not hasattr(main, '__file__')
我发现此方法非常有用,因为我在笔记本电脑上做了很多原型设计。出于测试目的,我使用默认参数。否则,我从中读取参数sys.argv
。
from sys import argv
if is_interactive():
params = [<list of default parameters>]
else:
params = argv[1:]
实施之后autonotebook
,您可以使用以下代码判断您是否在笔记本中。
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()
不能区分笔记本电脑和控制台。
%run
从ipython发出a的另一个警告是非交互式的。您可能会争辩它应该是,但这仍然是一个陷阱。
is_interactive
我看来,前半部分(大约)与该问题基本无关。它的正确性也令人怀疑。正如@marscher指出的那样,python -c
即使不是这样,它也会将运行的所有内容都视为处于“交互”模式。我不想自己做,因为这不是我的答案,但是我认为,只需删除答案的整个前半部分,就会有所改善。
最近,我在Jupyter笔记本电脑中遇到了一个错误,需要解决方法,我想做到这一点而又不损失其他Shell的功能。我意识到,keflavich的解决方案在这种情况下不起作用,因为get_ipython()
只能直接从笔记本电脑上使用,而不能从导入的模块上使用。因此,我找到了一种从模块中检测它是否从Jupyter笔记本中导入和使用的方法:
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
如果这足够健壮,请多加评论。
以类似的方式可以获取有关客户端以及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.modules
为False
。也许你的意思是'IPython' in sys.modules
?这是True
在我的Jupyter环境中。该sys.modules
词典还没有包括的'ipykernel'
关键-一个笔记本中运行时。
以下内容捕获了https://stackoverflow.com/a/50234148/1491619的情况,而无需解析以下内容:ps
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
它是否是一个jupyter console
,jupyter qtconsole
或jupyter notebook
。
我建议避免检测特定的前端,因为它们太多了。相反,您可以只测试是否在iPython环境中运行:
def is_running_from_ipython():
from IPython import get_ipython
return get_ipython() is not None
False
如果您是running_from_ipython
从通常的python命令行调用的,则以上内容将返回。当您从Jupyter Notebook,JupyterHub,iPython shell,Google Colab等调用它时,它将返回True
。
get_ipython()
返回<ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>
。
get_ipython() is not None
返回True
。
您所要做的就是将这两个单元格放在笔记本的开头:
单元格1 :(标记为“代码”):
is_notebook = True
单元格2 :(标记为“原始NBConvert”):
is_notebook = False
第一个单元格将始终被执行,但是仅当您将笔记本导出为Python脚本时才会执行第二个单元格。
稍后,您可以检查:
if is_notebook:
notebook_code()
else:
script_code()
希望这可以帮助。
据我所知,这里有3种使用过的ipython ipykernel
ipython qtconsole
(简称“ qtipython”)使用'spyder' in sys.modules
可以区分间谍
但是对于qtipython和jn很难区分原因
它们具有相同sys.modules
且相同的IPython配置:get_ipython().config
我在qtipython和jn之间发现了不同之处:
首先os.getpid()
在IPython shell中运行的会获得pid号
然后跑 ps -ef|grep [pid number]
我的qtipython pid是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
我的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
qtipython和jn的不同之处在于ipython的json名称,jn的json名称比qtipython的更长
因此,我们可以通过以下代码自动检测所有Python环境:
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)
假设您可以控制Jupyter Notebook,则可以:
在单元格中设置一个环境值,将该环境值用作代码中的标志。在该单元格(或您要排除的所有单元格)中添加唯一注释
#exclude_from_export
%set_env is_jupyter = 1
将笔记本导出为python脚本,以便在其他上下文中使用。导出将排除注释的单元格,并随后排除设置环境值的代码。注意:将your_notebook.ipynb替换为实际笔记本文件的名称。
jupyter nbconvert --to脚本--RegexRemovePreprocessor.patterns =“ ['^#exclude_from_export']” your_notebook.ipynb
这将生成一个没有设置jupyter环境标志的文件,允许使用它的代码确定性地执行。