Reset underscore (`_`) variable in Jupyter notebook powered by IPython kernel

ε祈祈猫儿з 提交于 2020-05-28 03:07:46

问题


Edit: The issue has been reported in GitHub. I'm leaving the question here in case it helps other people find the issue (I was not able to).


I often use the _ variable for convenience when working in a Jupyter notebook (it returns the output of the latest code execution). However, when _ is used to as a placeholder for an unused variable (a typical use case in Python), it breaks the first use case.

Note that this works as expected in an IPython console. Below, _ again holds the latest returned value after being used as an unused placeholder in the loop.

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'

However, after running the same code in a Jupyter notebook, _ will forever hold 1 (the last value from the loop), no matter what the latest output is. If I try to del _, then _ will no longer be an accessible variable.

In short, the two uses of the _ variable in Python clash in a Jupyter notebook, but not in an IPython console. It's only an inconvenience, but I would be curious to know how to solve it - or why it is.


Edit:

$ python --version
Python 3.6.3 :: Anaconda, Inc.
$ ipython --version
6.5.0
$ jupyter notebook --version
5.6.0

回答1:


Accooding to IPython source code ../lib/site-packages/IPython/core/displayhook.py 197 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

To recover underscore variable functionality,just run this code in 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]




回答2:


One safe way to get the result of the last execution (bypassing the special use of the underscore) is:

from IPython import get_ipython

ipython = get_ipython()

_ = ipython.last_execution_result.result

If the last execution did not have a result, then the above will set underscore to None.

So, this will not (necessarily) get the result of the last execution that had a result.

When the special meaning of underscore is still intact, it will be the result of the last execution that had a result (basically skipping None values).

To get that behavior is a little bit more involved.

If your code executes in the global context (so, not in a library), then you can do:

_ = Out.get(max(Out.keys(), default=0))

When there is no execution with a result, this will set underscore to None.

If your code executes in a library, and you don't want to pass in globals(), then you can do:

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

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


来源:https://stackoverflow.com/questions/56734319/reset-underscore-variable-in-jupyter-notebook-powered-by-ipython-kernel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!