如何在使用IPython内核的Jupyter笔记本中重置下划线(`_`)变量

4

编辑: 这个问题已经在GitHub中报告。我将保留这个问题,以便其他人可以找到该问题(我自己没有找到)。


当在Jupyter笔记本中工作时,我经常使用_变量来方便地返回最新代码执行的输出。然而,在Python中,当_用作未使用的变量占位符(这是一个典型的用例)时,它会破坏第一个用例。

请注意,在IPython控制台中,这一点与预期相符。下面,_再次在循环中被用作未使用的占位符后返回了最新的值。

In [1]: 'value'
Out[1]: 'value'

In [2]: _
Out[2]: 'value'

In [3]: for _ in range(2):
   ...:     print('hello')
   ...:     
hello
hello

In [4]: _
Out[4]: 1

In [5]: 'value'
Out[5]: 'value'

In [6]: _
Out[6]: 'value'

然而,在Jupyter Notebook中运行相同的代码后,_将永远保持为1(循环的最后一个值),无论最新的输出是什么。如果我尝试使用del _,那么_将不再是可访问变量。
简而言之,在Python中_变量的两种用法在Jupyter Notebook中冲突,但在IPython控制台中不会。这只是一个不便,但我很想知道如何解决它-或者为什么会这样。
$ python --version
Python 3.6.3 :: Anaconda, Inc.
$ ipython --version
6.5.0
$ jupyter notebook --version
5.6.0

是的。如果我将每个IPython“单元格”复制粘贴到尽可能多的Jupyter笔记本单元格中,则最终“_”将保存“1”,而不是“'value'”。 - IanS
如果你重写 Python 中的所有“保留”名称,原始使用就会消失,这一点也与其他名字相同。 如果您分配 print="fo", 您将无法再打印任何东西。>>> print(a) Traceback (most recent call last): File "", line 1, in TypeError: 'str' object is not callable >>>``` 此时您可以使用双下划线作为一个丢弃变量。例如:`for __ in range(2):` - Bendik Knapstad
1
请在此处查看错误报告(https://github.com/ipython/ipython/issues/11325)。 - rtoijala
@rtoijala 我找了一下,但没找到,谢谢! - IanS
1
@BendikKnapstad 双下划线和三下划线也是变量,分别表示之前执行的2次和3次。 - Luiz Ferraz
显示剩余3条评论
2个回答

3

根据 IPython 源代码 ../lib/site-packages/IPython/core/displayhook.py 中的 update_user_ns 函数。

            update_unders = True
            for unders in ['_'*i for i in range(1,4)]:
                if not unders in self.shell.user_ns:
                    continue
                if getattr(self, unders) is not self.shell.user_ns.get(unders):
                    update_unders = False

            self.___ = self.__
            self.__ = self._
            self._ = result

为了恢复下划线变量的功能,请在ipython repl中运行以下代码。
out_len=len(Out)
for index,n in enumerate(Out):
    if index==out_len-1:   _=Out[n]
    if index==out_len-2:  __=Out[n]
    if index==out_len-3: ___=Out[n]
    if index==out_len-4:____=Out[n]


1
嗯...你的代码对我不起作用。现在“_”永远是“[]”... - IanS

2

获得上一个执行结果的安全方式(避免使用下划线的特殊用法)是:

from IPython import get_ipython

ipython = get_ipython()

_ = ipython.last_execution_result.result

如果上一次执行没有结果,那么以上代码将把下划线设置为None
因此,这并不一定会得到上一个有结果的执行的结果。
当下划线的特殊含义仍然存在时,它将是最后一个有结果的执行的结果(基本上跳过None值)。
要获得该行为需要更多的步骤。
如果您的代码在全局上下文中执行(因此不在库中),则可以执行以下操作:
_ = Out.get(max(Out.keys(), default=0))

当没有执行结果时,这将把下划线设置为None

如果您的代码在库中执行,并且不想传递globals(),那么可以这样做:

out_hist = ipython.history_manager.output_hist  # ipython as set above

... out_hist.get(max(out_hist.keys(), default=0)) ...

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