Will the single underscore `_` in the REPL never be None?

Hi there

I understand that a single underscore _ in the REPL represents the last evaluated value.
But, in fact:

Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> None
>>> _
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_' is not defined

If an expression is evaluated to be None, _ is expected to be None.
Isn’t this reasonable?
If not, an alternative idea would be to assign _ to None at the startup of the REPL.
What do you think?
Before I report this to the issue tracker, I would like to hear your opinion.
Thanks in advance!

I think there’s a reason for the behaviour.

Here’s an example of what you might do:

>>> 1 + 2
3
>>> _
3
>>> print(_)
3
>>> _
3

print returns None, so if the REPL always bound the result to _, it would end as None.

The REPL won’t print the result if it’s None. That’s fine if you’re using print, which returns None, but other times you want it to print the result, whatever it is. You can use print for that:

>>> d = {0: 'zero', 1: 'one'}
>>> s = d.get(2)
>>> s
>>> print(s)
None

But if the result was in _ and you printed it, _ would be overwritten with None.

So, the current behaviour is a compromise.

1 Like

Thank you for your reply.
I understand that it is a compromise and that the result of print should be ignored.

That being said, the following example seems still confusing.

>>> 0 and None
0
>>> 0 or None
>>> _
0

The other compromising change would be:

  1. Assign _ to None if the last expression is None, except that it is the result of functions or methods.
    or
  2. Assign _ to None at the startup of the REPL.

Adopting the idea [2] avoids at least the exception shown in the first post.
Thoughts?

That’s very magical and very confusing.

You can actually do this one yourself.

rosuav@sikorsky:~$ echo '_ = None' > startup.py
rosuav@sikorsky:~$ PYTHONSTARTUP=startup.py python3
Python 3.12.0a6+ (heads/main:72186aa637, Mar 18 2023, 09:14:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print(_)
None

Stick this file in a convenient location, have the environment variable set globally (in your shell startup script or something), and you can pre-execute whatever commands you like as the REPL begins.

Hi Chris,
Thank you for your reply.

Unfortunately, it will give even more confusing results.

Python 3.11.4 (tags/v3.11.4:d2340ef, Jun  7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> _
>>> 1
1
>>> _
>>>

However, it gave me a hint of the correct solution:

# pythonstartup file
import builtins
builtins._ = None

Thank you!

2 Likes

Oh yeah, whoops. My bad. Forgot that it was set in the builtins rather than the globals. In any case, you figured it out from there, and you have the power to do it.

1 Like

I guess you could also change displayhook to your liking, use a modified version of the pseudo-code that doesn’t ignore None.

1 Like

Hi Stefan,
Thank you for the suggestion.
I tried and it worked, but I realized it is not good for printing…

Python 3.11.4 (tags/v3.11.4:d2340ef, Jun  7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> None
None
>>> print(1)
1
None
>>>

Nice hack @komoto48g, this is currently the best solution. I really wished they just set the _ to None by default on startup and we didn’t have to create a startup file and set environment variables just to set _ to None.