Re: v1.0.2 question

Guido.van.Rossum@cwi.nl
Thu, 05 May 1994 10:56:58 +0200

Tommy:
> > Python 1.0.2 (May 4 1994)
> > Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam
> > >>> vars()
> > {'__name__': '__main__', '_': {'__name__': '__main__', '_':
> > {'__name__': '__main__', '_': {'__name__': '__main__', '_':
> > {'__name__': '__main__', '_': {'__name__': '__main__', '_':
> > ... endless repetitions
>
> > The output I got was not what I expected. Was this a bug?

Tim:
> Maybe not strictly, but it is a hoot <grin>! The new feature is that '_'
> is automatically set to the result of the last auto-printed expression.
> So I think what's happening is:
>
> 1) vars() returns the namespace N == {'__name__': '__main__'}.
>
> 2) The auto-printer '_' hack binds '_' to N before printing, which
> changes the namespace to N == {'__name__': '__main__, '_': N}.
>
> 3) The attempt to print N == {'__name__': '__main__, '_': N} then falls
> into infinite recursion.
>
> At least that matches the symptoms.

Mea maxima culpa! Tim's explanation is correct.

If you are bothered by this, and don't mind losing the '_' variable,
you can take it out -- here's a temporary patch:

===================================================================
RCS file: /hosts/voorn/ufs/guido/python-RCS/new/Python/RCS/ceval.c,v
retrieving revision 2.64.2.7
diff -c -r2.64.2.7 ceval.c
*** 2.64.2.7 1994/05/04 07:41:12
--- ceval.c 1994/05/05 08:46:19
***************
*** 644,652 ****
case PRINT_EXPR:
v = POP();
/* Print value except if procedure result */
! /* Before printing, also assign to '_' */
! if (v != None &&
! (err = dictinsert(f->f_locals, "_", v)) == 0) {
flushline();
x = sysget("stdout");
softspace(x, 1);
--- 644,650 ----
case PRINT_EXPR:
v = POP();
/* Print value except if procedure result */
! if (v != None) {
flushline();
x = sysget("stdout");
softspace(x, 1);
===================================================================

You can of course also refrain from using vars(), or use "print
vars()" instead of "vars()".

Tommy again, in a later message:
> At the same time Guido proposed '_' as the value of the last
> printed expression, I believe he also proposed a list of the
> previously printed values that would be stored in something like
> 'sys.last' so 'sys.last[-1]' would be the last printed value. This
> sounds like the only thing we'd need, so we can trash this
> recursion-causing '_' variable and just store the last-value in
> sys.last. Or maybe last would be the list of values and we could have
> a separate var (sys.last_value?) to store the VERY last value printed.

That's a possibility, but I rather like the short name '_'! The whole
point of it is having a *shorthand* for the last calculated expression
in a calculator-like mode of use. A shorthand with a name like
'sys.last_value' doesn't strike me as particularly short and would
probably not be used much.

One way to almost-fix it would be to store the variable '_' in the
module __builtin__. In that way, it can still be used without
prefixing it with a module, but typing vars() won't go into recursion.
(vars(__builtin__) would, but that's a lot less likely to be called --
and sys.last_value would have the same problem with vars(sys).)

Beyond that, the routines that print mutable objects like lists and
dictionaries would have to be fixed to trap recursion somehow. This
seems like a tedious job (keep a stack of objects already being
printed) and there's the question, WHAT to print instead of the
recursive object?

--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>
URL: <http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>