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

时间:2013-03-14 14:25:45

标签: python ipython ipython-notebook

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

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

14 个答案:

答案 0 :(得分:39)

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

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

答案 1 :(得分:27)

以下内容符合我的需求:

get_ipython().__class__.__name__

它在终端IPython上返回'TerminalInteractiveShell',在Jupyter上返回'ZMQInteractiveShell'(笔记本和qtconsole)并在常规Python解释器上失败(NameError)。默认情况下,启动IPython时,方法get_python()似乎在全局命名空间中可用。

将其包装在一个简单的函数中:

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测试的。

答案 2 :(得分:16)

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

答案 3 :(得分:12)

最近我遇到了需要解决方法的bug in Jupyter notebook,我想在不丢失其他shell的功能的情况下这样做。我意识到keflavich's solution在这种情况下不起作用,因为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']

答案 4 :(得分:8)

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

我们在IPython中尽力阻止内核知道连接的是哪种前端,实际上你甚至可以同时连接到许多不同的前端。即使您可以查看stderr/out的类型以了解您是否在ZMQ内核中,它也不会保证您在另一方拥有的内容。你甚至可以没有任何前端。

您应该以独立于前端的方式编写代码,但如果要显示不同的内容,可以使用rich display system (link pinned to version 4.x of IPython)根据前端显示不同的内容,但前端会选择,而不是库。

答案 5 :(得分: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

答案 6 :(得分:2)

这样的事情如何?

import sys

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

print(inJupyter);

答案 7 :(得分:2)

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

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

is_notebook = True

单元2 :(标记为“原始NB转换”):

is_notebook = False

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

稍后,您可以检查:

if is_notebook:
    notebook_code()
else:
    script_code()

希望这会有所帮助。

答案 8 :(得分:1)

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

的ipython
  1. ipython qtconsole(简称“qtipython”)
  2. spyder的IPython(简称“spyder”)
  3. jupyter笔记本中的IPython(简称“jn”)
  4. 使用'spyder' in sys.modules可以区分spyder

    但是对于qtipython和jn很难区分原因

    他们有相同的sys.modules和相同的IPython配置:get_ipython().config

    我发现qtipython和jn之间有所不同:

    首先在IPython shell中运行os.getpid()获取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)
    

    源代码在这里: Detection Python Environment, Especially distinguish Spyder, Jupyter notebook, Qtconsole.py

答案 9 :(得分:1)

经过python 3.7.3测试

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

hasattr(__builtins__,'__IPYTHON__')

答案 10 :(得分:1)

一个非常简单有效的解决方案是检查调用栈顶是否指向IPython环境,如下:

import traceback

def is_in_notebook():
    rstk = traceback.extract_stack(limit=1)[0]
    return rstk[0].startswith("<ipython")

此代码适用于 Python 2 和 3,在 IPython 或 Jupyter 上,无需检查、设置或更改环境。

答案 11 :(得分:0)

我正在使用Django Shell Plus推出IPython,我想在笔记本电脑上运行&#39;可用作Django设置值。加载设置时get_ipython()不可用,所以我使用它(这不是防弹的,但对于它所使用的本地开发环境来说足够好):

import sys

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

答案 12 :(得分:0)

我建议避免检测特定的前端,因为有too many of them。相反,您可以只测试是否在iPython环境中运行:

def is_running_from_ipython():
    from IPython import get_ipython
    return get_ipython() is None

如果您是从常规python命令行调用running_from_ipython的,则上述返回True。当您从Jupyter Notebook,JupyterHub,iPython shell,Google Colab等调用它时,它将返回True。

答案 13 :(得分: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环境标志的文件,允许使用它确定执行的代码。