pre-PEP: Print Without Intervening Space

M

Marcin Ciura

Here is a pre-PEP about print that I wrote recently.
Please let me know what is the community's opinion on it.

Cheers,
Marcin


PEP: XXX
Title: Print Without Intervening Space
Version: $Revision: 0.0 $
Author: Marcin Ciura <marcin.ciura at polsl.pl>
Status: Draft
Type: Standards Track
Created: 11-Mar-2005
Post-History: 11-Mar-2005


Abstract

This PEP proposes to extend the syntax of the print statement
so that its space-insertion mechanism can be selectively
disabled by using double instead of single commas.


Rationale

The print statement can write several expressions in one line,
but presently always separates them with spaces. While this
behaviour is often desirable, not uncommon are situations, where
programmers have to use workarounds to achieve a non-spaced
display. This has been recognized as one of "Python Gotchas"
[1]. Even the simplest workaround results in an unnecessarily
complicated code (for the sake of simplicity let us assume that
fn() returns strings):

result = ''
for x in seq:
result += fn(x)
print result

Not to mention it also has a terrible algorithmic complexity.
None of the more efficient solutions is particularly
straightforward, either:

result = []
for x in seq:
result.append(fn(x))
print ''.join(result)

print ''.join([fn(x) for x in seq])

print ''.join(fn(x) for x in seq)

Moreover, all of them require creating one or two temporary
objects to hold the entire result. If the programmers use one of
them without qualms, it is only because their mind is warped by
the limitation of print.

Using write() is not especially appealing either, especially if
the print statements are used elsewhere in the code:

import sys
for x in seq:
sys.stdout.write(fn(x))
print # or sys.stdout.write('\n')

The proposed extension to the print statement is to use two
commas to signal that no space should be written after an
expression:

for x in seq:
print fn(x),,
print

To quote "The Zen of Python" [2]: "Beautiful is better than ugly.
Simple is better than complex. Readability counts."

The proposal applies also to the expressions in the middle of
the print statement. Thus it provides an alternative to string
concatenation and string interpolation, either with the '%'-based
specifiers, or with the '$'-based ones introduced by PEP 292 [3],
not requiring creating a temporary string object:

print 'The phone number is (',,extension,,')', number,,'.'

Note that I do not claim that the above version is any more
readable than

print 'The phone number is (%s) %s.' % (extension, number)


Specification

It is proposed to allow separating the expressions to be printed
by single or double commas, and to allow single or double commas
at the end of the print statement. The two commas shall be
consecutive, i.e. there shall be no whitespace between them.
Non-consecutive commas or any sequence of more than two commas
constitute a syntax error. In the "print chevron" form of the
statement, the name of the file object shall be separated from
the next expression only by a single comma, as it is now.

Formally, the proposed syntax of the extended print statement is

print_stmt: "print"
( [expression (("," | ",,") expression)* ["," | ",,"]]
| ">>" expression [(","
expression (("," | ",,") expression)* ["," | ",,"]]

Implementing the proposed syntax may require introducing a new
type of token: double comma, or a hack in the parser to recognize
two consecutive commas in the context of the print statement.

Two new byte codes, parallel to PRINT_ITEM and PRINT_ITEM_TO, are
needed to implement the semantics of the proposal.


Discussion

Pros:

- The proposed semantics allows avoiding temporary string objects
during the execution of the print statement and often makes for
more readable and explicit source code.

- The proposed syntax is easy to learn for the beginners.

- It breaks no existing Python code.

- Mistakes are unlikely to happen with the proposed syntax,
unless someone has problems with his typing or his keyboard,
in which case any programming is difficult, anyway.

Cons:

- Wrapper functions around print will be unable to mimic its
syntax. It is, however, impossible even now, due to trailing
commas.

- In PEP 259 [4], the BDFL has pronounced that he wants to avoid
any more tinkering with "print".

- PEP 3000 [5] and "Python Regrets" [6] state that the print
statement is to be replaced with a function in Python 3000,
so extending it may be a dead path.


References

[1] Python Gotchas, Steve Ferg:
http://www.ferg.org/projects/python_gotchas.html

[2] The Zen of Python, Tim Peters
http://www.python.org/doc/Humor.html

[3] PEP 292, Simpler String Substitutions, Barry A. Warsaw:
http://www.python.org/peps/pep-0292.html

[4] PEP 259, Omit printing newline after newline,
Guido van Rossum:
http://www.python.org/peps/pep-0259.html

[5] PEP 3000, Python 3.0 Plans, A.M. Kuchling, Brett Cannon:
http://www.python.org/peps/pep-3000.html

[6] Python Regrets, Guido van Rossum:
http://www.python.org/doc/essays/ppt/regrets/PythonRegrets.pdf


Copyright

This document has been placed in the public domain.


...
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
 
D

Duncan Booth

Marcin said:
None of the more efficient solutions is particularly
straightforward, either:

result = []
for x in seq:
result.append(fn(x))
print ''.join(result)

print ''.join([fn(x) for x in seq])

print ''.join(fn(x) for x in seq)

Moreover, all of them require creating one or two temporary
objects to hold the entire result. If the programmers use one of
them without qualms, it is only because their mind is warped by
the limitation of print.

I can't say I lose much sleep over this, but you could add my preferred
workaround to the list (I don't believe it suffers from the same drawbacks
as the options you propose) and say why your comma solution is better than
it:

import sys
def nospace(value, stream=None):
'''Suppress output of space before printing value'''
stream = stream or sys.stdout
stream.softspace = 0
return str(value)
print nospace(fn(i)),


<0><1><2><3><4><5><6><7><8><9>
 
M

Marcin Ciura

Duncan said:
import sys
def nospace(value, stream=None):
'''Suppress output of space before printing value'''
stream = stream or sys.stdout
stream.softspace = 0
return str(value)

I'm teaching Python as the first programming language to non-computer
scientists. Many of the toy programs would be simpler with the double
comma syntax. Presently, having a choice whether to teach my students
the result += fn(x) way or your way, I would still opt for the former.

Best regards,
Marcin
 
S

Steve Holden

Marcin said:
I'm teaching Python as the first programming language to non-computer
scientists. Many of the toy programs would be simpler with the double
comma syntax. Presently, having a choice whether to teach my students
the result += fn(x) way or your way, I would still opt for the former.

Best regards,
Marcin
You could think about teaching them the linelist.append(fn(x)) way,
which then gives you the choice of

"".join(linelist) - no gaps
"\n".join(lienlist) - one item per line
" ".join(linelist) - spaces between items.

regards
Steve
 
L

Larry Bates

Marcin said:
Here is a pre-PEP about print that I wrote recently.
Please let me know what is the community's opinion on it.

Cheers,
Marcin


PEP: XXX
Title: Print Without Intervening Space
Version: $Revision: 0.0 $
Author: Marcin Ciura <marcin.ciura at polsl.pl>
Status: Draft
Type: Standards Track
Created: 11-Mar-2005
Post-History: 11-Mar-2005


Abstract

This PEP proposes to extend the syntax of the print statement
so that its space-insertion mechanism can be selectively
disabled by using double instead of single commas.


Rationale

The print statement can write several expressions in one line,
but presently always separates them with spaces. While this
behaviour is often desirable, not uncommon are situations, where
programmers have to use workarounds to achieve a non-spaced
display. This has been recognized as one of "Python Gotchas"
[1]. Even the simplest workaround results in an unnecessarily
complicated code (for the sake of simplicity let us assume that
fn() returns strings):

result = ''
for x in seq:
result += fn(x)
print result

Not to mention it also has a terrible algorithmic complexity.
None of the more efficient solutions is particularly
straightforward, either:

result = []
for x in seq:
result.append(fn(x))
print ''.join(result)

print ''.join([fn(x) for x in seq])

print ''.join(fn(x) for x in seq)

Moreover, all of them require creating one or two temporary
objects to hold the entire result. If the programmers use one of
them without qualms, it is only because their mind is warped by
the limitation of print.

Using write() is not especially appealing either, especially if
the print statements are used elsewhere in the code:

import sys
for x in seq:
sys.stdout.write(fn(x))
print # or sys.stdout.write('\n')

The proposed extension to the print statement is to use two
commas to signal that no space should be written after an
expression:

for x in seq:
print fn(x),,
print

To quote "The Zen of Python" [2]: "Beautiful is better than ugly.
Simple is better than complex. Readability counts."

The proposal applies also to the expressions in the middle of
the print statement. Thus it provides an alternative to string
concatenation and string interpolation, either with the '%'-based
specifiers, or with the '$'-based ones introduced by PEP 292 [3],
not requiring creating a temporary string object:

print 'The phone number is (',,extension,,')', number,,'.'

Note that I do not claim that the above version is any more
readable than

print 'The phone number is (%s) %s.' % (extension, number)


Specification

It is proposed to allow separating the expressions to be printed
by single or double commas, and to allow single or double commas
at the end of the print statement. The two commas shall be
consecutive, i.e. there shall be no whitespace between them.
Non-consecutive commas or any sequence of more than two commas
constitute a syntax error. In the "print chevron" form of the
statement, the name of the file object shall be separated from
the next expression only by a single comma, as it is now.

Formally, the proposed syntax of the extended print statement is

print_stmt: "print"
( [expression (("," | ",,") expression)* ["," | ",,"]]
| ">>" expression [(","
expression (("," | ",,") expression)* ["," | ",,"]]

Implementing the proposed syntax may require introducing a new
type of token: double comma, or a hack in the parser to recognize
two consecutive commas in the context of the print statement.

Two new byte codes, parallel to PRINT_ITEM and PRINT_ITEM_TO, are
needed to implement the semantics of the proposal.


Discussion

Pros:

- The proposed semantics allows avoiding temporary string objects
during the execution of the print statement and often makes for
more readable and explicit source code.

- The proposed syntax is easy to learn for the beginners.

- It breaks no existing Python code.

- Mistakes are unlikely to happen with the proposed syntax,
unless someone has problems with his typing or his keyboard,
in which case any programming is difficult, anyway.

Cons:

- Wrapper functions around print will be unable to mimic its
syntax. It is, however, impossible even now, due to trailing
commas.

- In PEP 259 [4], the BDFL has pronounced that he wants to avoid
any more tinkering with "print".

- PEP 3000 [5] and "Python Regrets" [6] state that the print
statement is to be replaced with a function in Python 3000,
so extending it may be a dead path.


References

[1] Python Gotchas, Steve Ferg:
http://www.ferg.org/projects/python_gotchas.html

[2] The Zen of Python, Tim Peters
http://www.python.org/doc/Humor.html

[3] PEP 292, Simpler String Substitutions, Barry A. Warsaw:
http://www.python.org/peps/pep-0292.html

[4] PEP 259, Omit printing newline after newline,
Guido van Rossum:
http://www.python.org/peps/pep-0259.html

[5] PEP 3000, Python 3.0 Plans, A.M. Kuchling, Brett Cannon:
http://www.python.org/peps/pep-3000.html

[6] Python Regrets, Guido van Rossum:
http://www.python.org/doc/essays/ppt/regrets/PythonRegrets.pdf


Copyright

This document has been placed in the public domain.


..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:

I also don't miss a no-space option on print. I've always believed
that print statements with commas in them were for simple output with
little or no regard for formatting (like for debugging statements).
If I want precisely formatted output I use '%' formats or I build
the output line manually with joins or some other mechanism. The
''.join(seq) or ''.join([fn(x) for x in seq]) says exactly what
is being done to create the output string. I fail to see why
your proposed solution of:

for x in seq:
print fn(x),,
print

is clearer than:

print ''.join([fn(x) for x in seq])

Also your statement:

print 'The phone number is (',,extension,,')', number,,'.'

requires three double commas and can already be written
more clearly as:

print 'The phone number is ('+extension+') '+number'.'

or even more clearly (as you stated)

print 'The phone number is (%s) %s' % (extension, number)

Just my 2 cents.

Larry Bates
 
M

Marcin Ciura

Larry said:
I fail to see why
your proposed solution of:
for x in seq:
print fn(x),,
print
is clearer than:
print ''.join([fn(x) for x in seq])

Thank you for your input. The latter form is fine with me personally,
but you just can't explain it to complete novices. My proposal aims
at making programming easier for them.
Also your statement:
print 'The phone number is (',,extension,,')', number,,'.'
requires three double commas and can already be written
more clearly as:
print 'The phone number is ('+extension+') '+number'.'

I agree with you in this point (if extension and number are strings).

Best regards,
Marcin
 
B

Bill Mill

I also don't miss a no-space option on print. I've always believed
that print statements with commas in them were for simple output with
little or no regard for formatting (like for debugging statements).
If I want precisely formatted output I use '%' formats or I build
the output line manually with joins or some other mechanism. The
''.join(seq) or ''.join([fn(x) for x in seq]) says exactly what
is being done to create the output string.

I agree with everything said here. Furthermore, I don't like this PEP
because it introduces magic. When reading code, you just need to
magically know what the double-comma does in a print statement. Yes,
there are bits of magic involved in the solutions that already exist,
but I am opposed to the introduction of more.

Peace
Bill Mill
bill.mill at gmail.com
 
J

John Roth

I'm against further tinkering with Print on a number
of grounds, not least of which is that it's going
away in Python 3.0. It seems like wasted effort.

I don't see much difficulty with the current behavior:
if you want to get rid of the spaces, there are
alternatives.

I don't buy the novice arguement. If you want,
you can always implement your own print
function with a variable number of arguements
and just about any semantics you want.

John Roth





Marcin Ciura said:
Here is a pre-PEP about print that I wrote recently.
Please let me know what is the community's opinion on it.

Cheers,
Marcin


PEP: XXX
Title: Print Without Intervening Space
Version: $Revision: 0.0 $
Author: Marcin Ciura <marcin.ciura at polsl.pl>
Status: Draft
Type: Standards Track
Created: 11-Mar-2005
Post-History: 11-Mar-2005


Abstract

This PEP proposes to extend the syntax of the print statement
so that its space-insertion mechanism can be selectively
disabled by using double instead of single commas.


Rationale

The print statement can write several expressions in one line,
but presently always separates them with spaces. While this
behaviour is often desirable, not uncommon are situations, where
programmers have to use workarounds to achieve a non-spaced
display. This has been recognized as one of "Python Gotchas"
[1]. Even the simplest workaround results in an unnecessarily
complicated code (for the sake of simplicity let us assume that
fn() returns strings):

result = ''
for x in seq:
result += fn(x)
print result

Not to mention it also has a terrible algorithmic complexity.
None of the more efficient solutions is particularly
straightforward, either:

result = []
for x in seq:
result.append(fn(x))
print ''.join(result)

print ''.join([fn(x) for x in seq])

print ''.join(fn(x) for x in seq)

Moreover, all of them require creating one or two temporary
objects to hold the entire result. If the programmers use one of
them without qualms, it is only because their mind is warped by
the limitation of print.

Using write() is not especially appealing either, especially if
the print statements are used elsewhere in the code:

import sys
for x in seq:
sys.stdout.write(fn(x))
print # or sys.stdout.write('\n')

The proposed extension to the print statement is to use two
commas to signal that no space should be written after an
expression:

for x in seq:
print fn(x),,
print

To quote "The Zen of Python" [2]: "Beautiful is better than ugly.
Simple is better than complex. Readability counts."

The proposal applies also to the expressions in the middle of
the print statement. Thus it provides an alternative to string
concatenation and string interpolation, either with the '%'-based
specifiers, or with the '$'-based ones introduced by PEP 292 [3],
not requiring creating a temporary string object:

print 'The phone number is (',,extension,,')', number,,'.'

Note that I do not claim that the above version is any more
readable than

print 'The phone number is (%s) %s.' % (extension, number)


Specification

It is proposed to allow separating the expressions to be printed
by single or double commas, and to allow single or double commas
at the end of the print statement. The two commas shall be
consecutive, i.e. there shall be no whitespace between them.
Non-consecutive commas or any sequence of more than two commas
constitute a syntax error. In the "print chevron" form of the
statement, the name of the file object shall be separated from
the next expression only by a single comma, as it is now.

Formally, the proposed syntax of the extended print statement is

print_stmt: "print"
( [expression (("," | ",,") expression)* ["," | ",,"]]
| ">>" expression [(","
expression (("," | ",,") expression)* ["," | ",,"]]

Implementing the proposed syntax may require introducing a new
type of token: double comma, or a hack in the parser to recognize
two consecutive commas in the context of the print statement.

Two new byte codes, parallel to PRINT_ITEM and PRINT_ITEM_TO, are
needed to implement the semantics of the proposal.


Discussion

Pros:

- The proposed semantics allows avoiding temporary string objects
during the execution of the print statement and often makes for
more readable and explicit source code.

- The proposed syntax is easy to learn for the beginners.

- It breaks no existing Python code.

- Mistakes are unlikely to happen with the proposed syntax,
unless someone has problems with his typing or his keyboard,
in which case any programming is difficult, anyway.

Cons:

- Wrapper functions around print will be unable to mimic its
syntax. It is, however, impossible even now, due to trailing
commas.

- In PEP 259 [4], the BDFL has pronounced that he wants to avoid
any more tinkering with "print".

- PEP 3000 [5] and "Python Regrets" [6] state that the print
statement is to be replaced with a function in Python 3000,
so extending it may be a dead path.


References

[1] Python Gotchas, Steve Ferg:
http://www.ferg.org/projects/python_gotchas.html

[2] The Zen of Python, Tim Peters
http://www.python.org/doc/Humor.html

[3] PEP 292, Simpler String Substitutions, Barry A. Warsaw:
http://www.python.org/peps/pep-0292.html

[4] PEP 259, Omit printing newline after newline,
Guido van Rossum:
http://www.python.org/peps/pep-0259.html

[5] PEP 3000, Python 3.0 Plans, A.M. Kuchling, Brett Cannon:
http://www.python.org/peps/pep-3000.html

[6] Python Regrets, Guido van Rossum:
http://www.python.org/doc/essays/ppt/regrets/PythonRegrets.pdf


Copyright

This document has been placed in the public domain.


..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
 
M

Marcin Ciura

In view of Duncan's response, which invalidates the premises
of my proposal, I announce the end of its short life. I will
add Duncan's solution to my bag of tricks - thank you!
Marcin
 
B

Bengt Richter

I guess you are assuming fn(x) returns a string, or result knows how to
do += for whatever you are passing to it?

BTW, what makes you think any self-respecting "scientist" wouldn't be insulted
by the idea of your spoon-feeding them a dumbed-down programming equivalent of
"See Spot run"? IMO, if you were coaching althletes like that, you'd be fired,
because none of your team except the naturals would be able to run the length
of the ball field, and the natural athletes would have no use or respect for you.

Of course, you may be a suffering victim of circumstances, I don't know. Fortunately,
Python is not that hard, and rapidly becomes fun unless the initial experience
is structured against discovering the expressive power that is so enjoyable.

If you want the effect of print x, y, fn(z), etc without spaces, why don't you
just write a function that will let you spell it simply, like

marcinprint(x, y, fn(z), etc)

e.g., ... sys.stdout.write(''.join(map(str, args)))
... 1 two 3 4.5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'fn' is not defined

oops
1 two 3 4.5 64
1two34.564>>>

Might want to put a line ending on that ...
1two34.564

If you are used to C, you can get something familiar using
... sys.stdout.write(fmt %args)
...

Which you can use like
001 'two' 3 4.50 64
You could think about teaching them the linelist.append(fn(x)) way,
which then gives you the choice of

"".join(linelist) - no gaps
"\n".join(lienlist) - one item per line
" ".join(linelist) - spaces between items.
IMO teachers should lead their students into contact with reality,
not insulate them from it with delusionary simplifications that
they will have to unlearn in order to progress.

Regards,
Bengt Richter
 
M

Marcin Ciura

Steve said:
You could think about teaching them the linelist.append(fn(x)) way,
which then gives you the choice of
"".join(linelist) - no gaps
"\n".join(lienlist) - one item per line
" ".join(linelist) - spaces between items.

Sure I will. Next week, when we come to list operations.
..join() they already know. I just couldn't use this approach
at the very beginning. Thanks to all who responded.

Regards,
Marcin
 
H

huy

Marcin said:
I'm teaching Python as the first programming language to non-computer
scientists. Many of the toy programs would be simpler with the double
comma syntax. Presently, having a choice whether to teach my students
the result += fn(x) way or your way, I would still opt for the former.

Best regards,
Marcin


Since you're teaching python, why not teach the python way instead of
inventing a new way.

print 'The phone number is (%s) %s' % (extension, number)

IMO is by far the superior and clearest way for string concatenation for
any purpose eg. printing or assignment. This would mean you are making
your students lives easier by showing them one good method of doing
string concatenation which can be applied to printing as well.

Huy
 
M

Marcin Ciura

Bengt said:
BTW, what makes you think any self-respecting "scientist" wouldn't be insulted
by the idea of your spoon-feeding them a dumbed-down programming equivalent of
"See Spot run"?

Am I right thinking that your dream 3 R's curriculum starts with
"Stately, plump Buck Mulligan" and Pólya Enumeration Theorem?
Most of them have no previous programming experience, mind you.
Of course, you may be a suffering victim of circumstances, I don't know.

They're not so bad: I deliver the lectures (1.5 h/week), and there are
also laboratory classes (1.5 h/week). During one semester, most of
Python topics are covered.
Fortunately,
Python is not that hard, and rapidly becomes fun unless the initial experience
is structured against discovering the expressive power that is so enjoyable.

I wholeheartedly agree with you in this point. I'm sure my students
would appreciate being taught Python instead of Pascal if they had
a chance to compare them.
If you want the effect of print x, y, fn(z), etc without spaces, why don't you
just write a function that will let you spell it simply, like

Excellent advice, provided that you already know the concept
of user-defined functions.
IMO teachers should lead their students into contact with reality,
not insulate them from it with delusionary simplifications that
they will have to unlearn in order to progress.

I'm not sure what you mean by "delusionary simplifications",
but I hope you meant nothing insulting. They already know how to
use string interpolation, and as soon as they learn how to mutate
the contents of a list, I'll tell them to use looped .append()
followed by .join() instead of looped string concatenation,
and explain why.

Best regards,
Marcin
 
A

Antoon Pardon

Op 2005-03-11 said:
Moreover, all of them require creating one or two temporary
objects to hold the entire result. If the programmers use one of
them without qualms, it is only because their mind is warped by
the limitation of print.

Using write() is not especially appealing either, especially if
the print statements are used elsewhere in the code:

Personnaly I think just the reversed. I don't use print anywhere
unless for debugging purposes. I always use write
import sys
for x in seq:
sys.stdout.write(fn(x))
print # or sys.stdout.write('\n')

The proposed extension to the print statement is to use two
commas to signal that no space should be written after an
expression:

for x in seq:
print fn(x),,
print

To quote "The Zen of Python" [2]: "Beautiful is better than ugly.
Simple is better than complex. Readability counts."

IMO that favors using always write instead of using print with it
various extentions.

For instance if I do the following

a = 1,

I have assigned a one element tuple to a.

But if I do

print 1,

It doesn't print a one element tuple.
 
T

Thomas Bellman

Antoon Pardon said:
For instance if I do the following
a = 1,
I have assigned a one element tuple to a.
But if I do
print 1,
It doesn't print a one element tuple.

And if you do

parrot(1,)

you won't call parrot() with a one-element tuple either. However,
'parrot(1)' and 'parrot(1,)' means exactly the same thing, while
'print 1' and 'print 1,' does not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top