[Python-Dev] PEP 259: Omit printing newline after newline

Alex Martelli aleaxit at yahoo.com
Tue Jun 12 05:29:50 EDT 2001


"Roman Suzi" <rnd at onego.ru> wrote in message
news:mailman.992325753.25339.python-list at python.org...
> On Mon, 11 Jun 2001, Glyph Lefkowitz wrote:
>
> >I'm for it.  In fact, we should do things like this more often -- if the
> >semantics of "print" change once per release, everyone will stop using
it,
> >the keyword/bytecode will vanish, and people will use a function for
> >writing to standard out, as it should have been all along! :)
>
> Why do you insist on using function instead of print statement?
> Maybe, we can also eliminate del statement because there is no
> "new" cunterpart of it?

Axiom: a function does not affect its caller's namespace --
it does not bind, it does not unbind, it does not re-bind.

Lemma: any construct that, by design, must affect the "caller's"
namespace should not be a function, but rather a statement.

ObBadExample: execfile.  It's a statement in function's
clothing.  And thus, it works quite badly:

D:\py21>python
Python 2.1 (#15, Apr 16 2001, 18:25:49) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
Alternative ReadLine 1.4 -- Copyright 2001, Chris Gonnerman
>>> print open('fo.py').read()
a=23

>>> execfile('fo.py')
>>> a
23
>>> del a
>>> def f():
...     execfile('fo.py')
...     print a
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in f
NameError: global name 'a' is not defined
>>>
>>> def g():
...     a=5
...     execfile('fo.py')
...     print a
...
>>> g()
5
>>>

Clearly we do NOT want other such semi-working hacks -- one
is more than enough:-).

Therefore: assignment and del, whose PRIMARY purpose is
affecting the namespace in which they're used, MUST be
statements.  class, def, import, from, for, affect the
namespace in which they're used as part of their
operation -- this is maybe a secondary effect that is
not always wanted in the case of 'for', but it's very
much a part of normal operation for the others.  OK so
far...?  Oh, exec, too -- to ALLOW it to affect the
namespace in which it's used, specifically!

Another reason to make something a statement is when
the 'something' contains one or more blocks of code
and/or affects control flow. class, def and for meet
this test too.  while, if, try, raise, break, return,
continue -- all affect control flow.  pass can also
be seen this way -- it has NULL effect on control flow
(or anything else), making it a suitable place-holder
and allowing Python to avoid the syntax problems that
come with a "null statement" like in C & descendants.

So, summarizing: in Python, keyword statements either
affect the namespace using them, or affect the control
flow that uses them.

All, that is... except ONE.

That one is: print.  A keyword statement that neither
affects the namespace, nor control flow.  An anomaly,
therefore, that sticks out like a sore thumb.  Surely
not such a huge one that it's worth breaking 99% of
existing scripts to remove it:-).  *However* -- why
keep overloading it with magic and extra "convenience"
features...?  Glyph may be right in paradoxically
claiming that just such tweaking will eventually show
everyone that print is just best not used:-).

To HELP migration to a function for what is now done
with print, I think such a built-in function should be
added contextually to this latest 'print' change.  Yes,
yes, it IS un-Pythonic to provide several ways to do
the same task, but, here, I think, we need to patch
over the non-Pythonic existence of print itself:-).

I believe the new print-like built-in function should
ideally be named print, but we can't do it, because
keywords are reserved.  Sigh.  Among the alternatives,
we have: write (misleading as it recalls the write
method of file-objects), output (makes for a nice
pair with input, which, however, has its own nasty
problems:-), emit, say (a la Rexx), echo (a la sh),
and many others, including non-words that decorate
these basic words (doprint, etc).

Whatever name is used (assume 'output' for definiteness,
without loss of generality), I think the print-like
function should accept arbitrary unnamed arguments
(to be treated just like the items now passed to
print) optionally followed by named arguments to
supply the same tweaks that now print supplies (and
maybe a few more) -- names are doubtful, but...:
    file=sys.stdout   the output file-object to use
    newl=1            1 emit a newline at the end
                        UNLESS the last item printed
                        is a string ending in \n
                        (like print will now work)
                      0 no newline at the end (like
                        print with a trailing comma)
                      2 force newline at the end in
                        any case (like print today)
    (others?)

a la (2.2 syntax, untested):

def output(*args, **kwds):
    file = sys.stdout
    newl = 1
    for k in kwds:
        if k=='file': file=kwds[k]
        elif k=='newl': newl=kwds[k]
        else:
            raise TypeError, \
                "output() got an unexpected keyword argument '%s'"%k
    # I'm just approximating softspace behavior here...:
    soft = getattr(file, 'softspace', 0)
    no_end_nl = 1
    for a in args:
        if soft: file.write(' ')
        towrite = str(a)
        no_end_nl = towrite=='' or towrite[-1]!='\n'
        file.write(towrite)
        soft = file.softspace = no_end_nl
    if newl:
        file.softspace = 0
        if newl==2 or no_end_nl:
            file.write('\n')

Having output as a built-in function would encourage
using it in lieu of the print statement, which, in
turn, would allow the usual kind of tricks that are
available for built-ins but not for statements, such
as wrapping/overriding (you can do that for print with
a user-defined file-like object, to some extent, but
not fully -- the file-like object cannot know where
a given print statement begins or ends, it can only
intercept specific write and softspace accesses).


Alex






More information about the Python-list mailing list