IPython Notebook - 单元格的早期退出

92

我想在IPython Notebook中以编程方式提前退出一个单元格。然而,exit(0)会关闭内核。

有什么正确的方法吗?我不想拆分单元格或手动停止执行。

注: - IPython 是一个交互式计算、数据分析、可视化和编程环境,是 Python 的增强版。 - 单元格是 IPython Notebook 中的基本单位,可以在其中输入和运行代码,并且可以包含其他类型的内容(如文本、图像等)。

你能解释一下为什么吗?如果你决定只运行单元格中一半的代码然后停止,我猜你可以引发一个异常,但我不确定那有什么用处。 - Marius
1
@Marius:这是一种开发策略。我仍然喜欢在单个单元格中一次性运行大块代码,但经常想要查询变量状态而不运行整个程序。我对IPN相对较新,在以前使用命令行脚本进行开发时,我通常使用exit(0)来实现这一点。 - watsonic
@watsonic:我能想到的最接近你所需工作流程的方法是打开一个使用与笔记本相同内核的Ipython控制台,使用“ipython qtconsole --existing”命令,并在需要快速检查时将你实际想要运行的代码从笔记本复制粘贴到控制台中。 - Marius
@Marius:谢谢,但那比我想做的(复制粘贴等)要复杂一些。我认为IPN很好,因为它是自包含的。 - watsonic
一种方法是将您的代码放入一个函数中。然后使用return None提前退出 - 而不会抛出错误。 - Charlie
显示剩余7条评论
6个回答

62

稍微更“正规”的选项:

这将使你摆脱除了最糟糕的try/except块之外的所有问题。

raise KeyboardInterrupt

您的版本稍微简洁一些:

assert(False)

或者简单地说:

raise

如果您想节省几次按键。


31
问题在于这种方式很混乱,会出现回溯的情况。找到一个可以安静结束执行的解决方案会更好。 - Stephen

61
停止当前和后续单元格,保持安静。
class StopExecution(Exception):
    def _render_traceback_(self):
        return []

raise StopExecution

4
太棒了!非常简洁清晰! - manu3d
1
非常干净,谢谢!现在我可以执行“def exit(): raise StopExecution”。 - Micha F.
3
根据 https://github.com/ipython/ipython/blob/4f6e132d2fc56feabd9d87cac98906d3e5806d6a/IPython/core/interactiveshell.py#L1994 ,_render_traceback_ 应该返回字符串列表。因此,该方法应该使用 return [] 而不是 pass。当使用 nbconvert 时,使用 pass 会导致异常。 - Stan

26

我将我的回答从这里转载,因为解决方案也适用于你的问题。它将:

  • 不会在退出时终止内核
  • 不会显示完整的回溯(IPython shell 中没有回溯)
  • 不会强制你用 try/except 嵌套代码
  • 能够与或不使用 IPython,在不更改代码的情况下工作

只需从下面的代码中导入 'exit' 到你的 Jupyter 笔记本(IPython 笔记本),调用 'exit()' 就可以了。它会退出并让你知道...

 An exception has occurred, use %tb to see the full traceback.

 IpyExit 

"""
# ipython_exit.py
Allows exit() to work if script is invoked with IPython without
raising NameError Exception. Keeps kernel alive.

Use: import variable 'exit' in target script with
     'from ipython_exit import exit'    
"""

import sys
from io import StringIO
from IPython import get_ipython


class IpyExit(SystemExit):
    """Exit Exception for IPython.

    Exception temporarily redirects stderr to buffer.
    """
    def __init__(self):
        # print("exiting")  # optionally print some message to stdout, too
        # ... or do other stuff before exit
        sys.stderr = StringIO()

    def __del__(self):
        sys.stderr.close()
        sys.stderr = sys.__stderr__  # restore from backup


def ipy_exit():
    raise IpyExit


if get_ipython():    # ...run with IPython
    exit = ipy_exit  # rebind to custom exit
else:
    exit = exit      # just make exit importable

早期退出如何在Kaggle内核笔记本中使用? - shaurya airi
抱歉,@shauryaairi,我还没有使用过Kaggle,所以不清楚。 - Darkonaut
6
为什么没有内置的方法来做这件事? - Chris_Rands
如何隐藏“发生了异常,请使用%tb来查看完整的回溯信息。”? - undefined
据我记得,你不可以,这就是为什么答案提到你会收到这条消息。这个答案已经有点旧了,也许今天有我不知道的方法。 - undefined

4

并不是说这是一个好主意,但你可以使用单次迭代循环包装单元格的开始,然后调用“break”停止进一步执行。


for _ in range(1):
    # do some stuff
    if some_condition:
        break 


1
我认为这是一个优雅的解决方案。而且,如果我们在一个函数中重复使用代码(使用jupyter进行测试/原型设计),我们只需要将“break(s)”更改为“return”。 - am_technix

0

这并不是“规范”的做法,但一种早期退出的方法是创建运行时错误。因此,与使用exit(0)干净地从脚本返回不同,可以使用以下类似方式不干净地返回

print(variable_to_query)
() + 1

这将运行代码直到此时(完成打印语句),然后失败。


4
与插入不存在的变量或输入0/0等任何其他错误相比,有何不同之处? - aless80
没有区别。任意的 - watsonic

-1
一个简单的答案是将代码包装在一个函数内,并使用return语句来停止执行。
def func:
    if x==y:
        return

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接