111

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

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

4

14 回答 14

93

以下内容满足我的需求:

get_ipython().__class__.__name__

'TerminalInteractiveShell'在终端 IPython、'ZMQInteractiveShell'Jupyter(笔记本和 qtconsole)上返回,并NameError在常规 Python 解释器上失败()。启动 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 进行了测试

于 2016-09-23T13:43:35.997 回答
40

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

def in_ipynb():
    try:
        cfg = get_ipython().config 
        if cfg['IPKernelApp']['parent_appname'] == 'ipython-notebook':
            return True
        else:
            return False
    except NameError:
        return False
于 2014-07-24T15:04:56.937 回答
38

您可以使用以下代码段[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
    except AttributeError:
        return False
    return True
于 2014-03-15T14:05:07.860 回答
23

最近我在 Jupyter notebook中遇到了一个需要解决方法的错误,我想在不丢失其他 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']
于 2016-06-06T15:56:08.180 回答
6

已针对 python 3.7.3 测试

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

hasattr(__builtins__,'__IPYTHON__')
于 2019-09-25T16:12:52.430 回答
4

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

我们在 IPython 中尽最大努力防止内核知道连接到哪种前端,实际上您甚至可以让一个内核同时连接到许多不同的前端。即使您可以查看类型stderr/out以了解您是否在 ZMQ 内核中,但它并不能保证您在另一端拥有什么。你甚至可以根本没有前端。

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

于 2013-03-14T14:56:28.810 回答
3

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

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

is_notebook = True

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

is_notebook = False

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

稍后,您可以检查:

if is_notebook:
    notebook_code()
else:
    script_code()

希望这可以帮助。

于 2020-02-18T21:09:17.573 回答
2

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

  1. ipython qtconsole(简称“qtipython”)
  2. spyder中的IPython(简称“spyder”)
  3. jupyter notebook 中的 IPython(简称“jn”)

使用'spyder' in sys.modules可以区分spyder

但是对于 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 notebook、Qtconsole.py

于 2018-05-08T12:53:23.653 回答
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
于 2018-11-22T18:53:46.087 回答
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.

于 2019-03-03T10:33:18.417 回答
2

一个非常简单高效的解决方案是检查调用堆栈的顶部是否引用了 IPython 环境,如下:

import traceback

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

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

于 2021-05-20T14:29:08.657 回答
1

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

import sys

if '--notebook' in sys.argv:
    ENVIRONMENT = "notebook"
else:
    ENVIRONMENT = "dev"
于 2017-11-03T11:02:39.343 回答
1

假设您可以控制 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 环境标志的文件,允许使用它的代码确定性地执行。

于 2020-02-11T19:55:25.423 回答
1

像这样的东西怎么样:

import sys

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

print(inJupyter);
于 2020-02-18T15:20:08.037 回答