如何检查代码是否在IPython笔记本中执行?


89

我想分享一些Python代码示例,如果在终端Python / IPython或IPython笔记本中执行,则应该做一些不同的事情。

如何检查我的Python代码是否在IPython笔记本中运行?


3
我建议接受古斯塔沃·贝塞拉(Gustavo Bezerra)的回答。当前接受的答案无法回答问题,而Gustavo的答案是分数最高的答案,该答案仍在最新版本的Jupyter Notebook中有效。
Mark Amery

Answers:


9

问题是您想以不同的方式执行什么。

我们在IPython中尽力防止内核知道连接到哪种前端,实际上,您甚至可以同时将内核连接到许多不同的前端。即使您可以窥视一下stderr/out是否知道您是否在ZMQ内核中,它也不能保证您在另一端拥有什么。您甚至根本没有前端。

您可能应该以独立于前端的方式编写代码,但是如果要显示不同的内容,则可以使用丰富的显示系统(固定到IPython版本4.x的链接)根据前端显示不同的内容,但是前端会选择,而不是库。


2
上方指向IPython Rich Display System的链接已断开。这是当前文档的链接:ipython.org/ipython-doc/dev/config/integrating.html,这是一些出色示例的链接:nbviewer.ipython.org/github/ipython/ipython/blob/master/ …
Who8MyLunch 2014年

2
我的绘图模块中有这样的问题。我需要在其中导入调用matplotlib.use(“ Agg”)以便travis-ci允许保存图形(请参阅stackoverflow.com/questions/4706451/…),但这会在笔记本中生成警告UserWarning:此对matplotlib.use的调用()无效,因为已经选择了后端;如何解决呢?
Goulu博士2014年

30
我有一个例子:进度条。Jupyter笔记本电脑终端仿真器不支持扩展的终端控制字符,例如\x1b[A(向上移动),因此无法打印嵌套的条形图ipywidgets没问题,我们可以使用本机Jupyter小部件显示进度条。但是然后我们有两种不同的方式来显示进度条,并且应用程序可能想知道什么显示环境才能适应和打印兼容的条。
令人赞叹的

2
例如,我想将IPython配置设置为%matplotlib inline在充当笔记本时始终运行,但不在终端中运行,因为这不是必需的。
CiprianTomoiagă17年

3
虽然这是一个完全有效的意见,但此答案并未解决实际问题。无论您希望的是多少,否则在行为上总是存在差异的,这很重要。
克里斯托弗·巴伯

69

以下满足我的需求:

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进行了测试


5
jupyter console,不幸的是get_ipython()返回的实例ZMQInteractiveShell
约什-伯德

7
如果有人有兴趣检测笔记本是否正在Google Colab上运行,则可以进行以下检查:get_ipython().__class__.__module__ == "google.colab._shell"
guiferviz

3
这仅适用于笔记本中的代码。如果该功能在导入的程序包中,则该功能不起作用。
克里斯托弗·巴伯

4
@ChristopherBarber那不是我看到的。如果我将此功能粘贴到文件中,test.py然后from test import isnotebook; print(isnotebook())在Jupyter Notebook中运行,它将打印True。(在笔记本服务器版本5.2.1和6.0.1上进行了测试。)
Mark Amery

我认为有些情况对我不起作用,但不幸的是我不记得细节了。也许这不再是问题,或者我只是感到困惑。
Christopher Barber

41

要检查您是否在笔记本中,这可能很重要,例如,在确定要使用哪种进度条时,这对我有用:

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False

6
在我的IPython-Notebook(IPython版本3.1)中,cfg['IPKernelApp']['parent_appname']IPython.config.loader.LazyConfigValue,它True"iypthon-notebook"
Dux

5
@juanjux get_ipythonIPython.kernel.zmq.zmqshell.ZMQInteractiveShell在ipynb(Jupyter)中返回一个实例,并IPython.terminal.interactiveshell.TerminalInteractiveShell在终端REPL中返回一个实例,以防您需要区分笔记本和终端/控制台(这会影响绘图)。
滚刀

4
^因此,您可以将try块的内部替换为:return str(type(get_ipython())) == "<class 'ipykernel.zmqshell.ZMQInteractiveShell'>"
user2561747

像@Dux一样,这对我不起作用;即使在笔记本中,它始终返回false。怀疑随着某种惰性配置加载系统的引入,这个答案已经过时了。
Mark Amery

还要注意,您的配置可能会作为空字典返回,在这种情况下,您需要将KeyError添加到except块中。但是,最好使用基于Gustavo Bezerra的答案的代码。即使我得到一个空的配置,shell='PyDevTerminalInteractiveShell'在检查类名时也会得到。
hlongmore

28

您可以使用以下代码段[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

python -c“ def is_interactive():>导入main作为main>返回not hasattr(main,' file ')> print is_interactive()” True
marscher 2015年

3
is_interactive()不能区分笔记本电脑和控制台。
krock 2015年

1
%run从ipython发出a的另一个警告是非交互式的。您可能会争辩它应该是,但这仍然是一个陷阱。
dirkjot

对于笔记本中的其他原型,此处介绍的Till方法的变体可能会很有用。
韦恩

该答案的后半部分很有用,但在is_interactive我看来,前半部分(大约)与该问题基本无关。它的正确性也令人怀疑。正如@marscher指出的那样,python -c即使不是这样,它也会将运行的所有内容都视为处于“交互”模式。我不想自己做,因为这不是我的答案,但是我认为,只需删除答案的整个前半部分,就会有所改善。
Mark Amery

17

最近,我在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']

嗯,我正在使用Fedora 23 Jupyter,结果'Ipython' in sys.modulesFalse。也许你的意思是'IPython' in sys.modules?这是True在我的Jupyter环境中。该sys.modules词典还没有包括的'ipykernel'关键-一个笔记本中运行时。
maxschlepzig '16

2
到目前为止,这是最好的答案,IMO。简短而甜美。
danielpcox

3

经过python 3.7.3测试

CPython实现的名称__builtins__可以用作其全局变量的一部分。可以通过函数globals()检索。
如果脚本在Ipython环境中运行,__IPYTHON__则应为的属性__builtins__
因此,True如果在Ipython下运行,则下面的代码返回,否则给出False

hasattr(__builtins__,'__IPYTHON__')

2

以下内容捕获了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 consolejupyter qtconsolejupyter notebook
卢克·戴维斯

2

我建议避免检测特定的前端,因为它们太多了。相反,您可以只测试是否在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


对我不起作用-当我在具有Python3的Ubuntu上的Jupyter Notebook中尝试此操作时,get_ipython()返回<ipykernel.zmqshell.ZMQInteractiveShell at 0x7f750ba94320>
主角

这种方法的问题在于它不能解决OP的问题:“如何在我的Python代码中检查它是否在IPython笔记本中运行?” (强调我的)。IPython shell不是笔记本,但是当我在PyCharm的Python控制台中运行它时,我会get_ipython() is not None返回True
hlongmore

嗯,如何检测我是否在jupyter vs voila上运行?
ntg

2

您所要做的就是将这两个单元格放在笔记本的开头:

单元格1 :(标记为“代码”):

is_notebook = True

单元格2 :(标记为“原始NBConvert”):

is_notebook = False

第一个单元格将始终被执行,但是仅当您将笔记本导出为Python脚本时才会执行第二个单元格。

稍后,您可以检查:

if is_notebook:
    notebook_code()
else:
    script_code()

希望这可以帮助。


2

这样的事情怎么样:

import sys

inJupyter = sys.argv[-1].endswith('json')

print(inJupyter);

1

据我所知,这里有3种使用过的ipython ipykernel

  1. ipython qtconsole (简称“ qtipython”)
  2. Spyder中的IPython(简称“ spyder”)
  3. Jupyter笔记本中的IPython(简称“ jn”)

使用'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)

源代码在这里:检测Python环境,特别是区分Spyder,Jupyter笔记本,Qtconsole.py


0

我正在使用Django Shell Plus启动IPython,我想将“在笔记本中运行”作为Django设置值提供。get_ipython()在加载设置时不可用,因此我使用了它(这不是防弹的,但对于它所使用的本地开发环境来说已经足够了):

import sys

if '--notebook' in sys.argv:
    ENVIRONMENT = "notebook"
else:
    ENVIRONMENT = "dev"

0

假设您可以控制Jupyter Notebook,则可以:

  1. 在单元格中设置一个环境值,将该环境值用作代码中标志。在该单元格(或您要排除的所有单元格)中添加唯一注释

    #exclude_from_export
    %set_env is_jupyter = 1

  2. 将笔记本导出为python脚本,以便在其他上下文中使用。导出将排除注释的单元格,并随后排除设置环境值的代码。注意:将your_notebook.ipynb替换为实际笔记本文件的名称。

    jupyter nbconvert --to脚本--RegexRemovePreprocessor.patterns =“ ['^#exclude_from_export']” your_notebook.ipynb

这将生成一个没有设置jupyter环境标志的文件,允许使用它的代码确定性地执行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.