Please hear my plea: print without softspace

J

Josiah Carlson

If a '+' is problematic, it could be some other character. If I use
a print statement in a Python program, from my viewpoint, a
trailing comma signals suppression of newline and adding a space.
In this scenario, a trailing <insert acceptable character here>
would suppress the newline but not add a space. There's not much
difference there.

The problem is that checking my keyboard, there exists exactly three
characters without syntactical meanings in Python 2.3; @, $, ?. None of
them make /any/ sort of syntactical sense to me in this context. I hope
that Guido feels the same way.

Having said all that, I'll add that I don't see this as a big
issue, and I don't find it a burden to use an alternative syntax to
achieve the same effect. I don't know how to tell if it's a right
or wrong thing to do. If it were a feature of the language, I'd
probably use it. I've never really understood what it is about the
print statement that bothers some people; it's always seemed
reasonably useful and reasonably intuitive to me. Maybe every
language is destined to have irregular verbs.

I don't know if every language is destined, and I don't find print to be
all that irregular, or really magical, so it seems like we are on the
same page.


- Josiah
 
P

Paul Rubin

Josiah Carlson said:
The problem is that checking my keyboard, there exists exactly three
characters without syntactical meanings in Python 2.3; @, $, ?. None
of them make /any/ sort of syntactical sense to me in this context. I
hope that Guido feels the same way.

How about two trailing commas:

print foo

now prints foo with a trailing newline.

print foo,

suppresses the trailing newline but adds a trailing space.

print foo,,

can suppress the trailing space as well.
 
J

Josiah Carlson

How about two trailing commas:
print foo

now prints foo with a trailing newline.

print foo,

suppresses the trailing newline but adds a trailing space.

print foo,,

can suppress the trailing space as well.

Do you really want to see the following;

print "hello ",,"world"


IMO, if people really want to have precise control over their program
output, then they should be using sys.stdout.write(), printf-style
string formatting, or both. For me, I see print as a convenience, not
as a one-function-fits-all-for-all-program-output.

- Josiah
 
G

Gerrit

Josiah said:
It seems that you are saying:

print "hello ", "world" + #-> "hello world"

That looks like "magic syntax", and should rightfully return a syntax
error, because + already has a meaning for most all data types in
Python. Changing the behavior of print when a syntax error is present,
is the wrong thing to do.

It can be done the other way around:.... def __pos__(self):
.... if self.endswith(' '): return self[:-1]
.... else: return self
....abc bla

....although I prefer sys.stdout.write.

Gerrit.
 
D

David MacQuigg

The right thing to do is to put make stdout a builtin and deprecate the
print statement. The "smart" behavior of the print statement causes more
trouble than it's worth. I admit that I use the print statement myself
occasionally, but only because 'sys.stdout.write' is too long to type all
the time, and never with more than one argument.

The 'print' statement is just shortcut for 'sys.stdout.write' with
some convenience features suitable for most users. If you need
something else, just define your own shortcut, don't deprecate a
statement that is exactly what most users want.
abcxyz
abcxyz

Now you have explicit control over the \n, and the new statement
(including parens) is the same number of characters as 'print'.

We need to resist the temptation to *change* the core language, when
*extending* it using normal function syntax is so easy.

Note: You can also change the behavior of 'print' by redefining
'sys.stdout.write'. You can even hide that redefinition deep in some
imported module, where future maintainers of your code will never find
it. :>)

-- Dave
 
M

Martin Bless

[David Goodger said:
you should write a PEP. Without a PEP, the idea will be forgotten.

Good advice, good encouragement, thanks.

I'd really like to. But unfortunately I've discovered the weak point
in my own argumentation: a new keyword could and probably would break
existing code. Therefore I can't go for a PEP until I have a better
idea.

Ok, then let's use some wrappers or helper functions. Here's the one I
currently like:

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
"""Do some experiments on write statements."""

__author__ = "Martin Bless, 2004-03-03"

class Writer:

def __init__(self,writer=None):
if writer is None:
import sys
self.writer = sys.stdout
else:
self.writer = writer

def write(self,*args):
for arg in args:
self.writer.write(str(arg))

__call__ = write

def to(self,writer,*args):
for arg in args:
writer.write(str(arg))

write = Writer()
NL = '\n'
import sys
stderr = Writer(sys.stderr)

if __name__=="__main__":
import sys
outfile = sys.stdout or file('demo_tempfile','w')
write('#', '-->'*10, NL)
write('Starting.',NL)
write(__doc__,NL)
write("write(1,2,3,4,NL)=>", 1,2,3,4,NL)
write("write('This',' ','is',' ','a',' ','demo.',NL)=>",
'This',' ','is',' ','a',' ','demo.',NL)
write.to( outfile,"write.to(outfile,5,6,7,8,NL)=>",5,6,7,8,NL)
stderr("stderr('A number in parentheses: (', 77, ').', NL)=>",
'A number in parentheses: (',77,').',NL)
write('Done.',NL)
write('#', '<--'*10, NL)

"""Output should be:
#-->-->-->-->-->-->-->-->-->-->
Starting.
Do some experiments on write statements.
write(1,2,3,4,NL)=>1234
write('This',' ','is',' ','a',' ','demo.',NL)=>This is a demo.
write.to(outfile,5,6,7,8,NL)=>5678
stderr('A number in parentheses: (',77,').',NL)=>A number in
parentheses: (77).
Done.
#<--<--<--<--<--<--<--<--<--<--
"""

This comes pretty close to what I was aiming at. But of course it's
just my version and different people will create different solutions.

mb - Martin Bless
 
M

Martin Bless

["Rainer Deyke said:
but only because 'sys.stdout.write' is too long to type all
the time, and never with more than one argument.

Yes, I feel it's a pity that the standard write method of file objects
doesn't take multiple arguments. Would take some of the pressure.

One thing I can do since Python-2.2 is to inherit from 'file' and add
for example a 'writem' (write many, write multiple) method. This does
work.

Unfortunately it seems I can't add that 'writem' method to sys.stdout,
as the following shows.

Anybody any ideas?


#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
"""Test file object."""

__author__ = "Martin Bless, 2004-03-03"

if 1 and "this does work":
class MyFile(file):

def writem(self,*args):
"Method to write many arguments."
for arg in args:
self.write(str(arg))

f2name = 'xxxtempfile'
f2 = MyFile(f2name,'w')
f2.writem(1,2,3,4)
f2.close()


if 1 and "this does not work with sys.stdout":
"""
Attempt to add a method to a class at runtime.
See Python Cookbook or ASPN,
Object-Oriented Programming, Brett Cannon.
"""
import sys
def writem(self,*args):
"Function to be turned into a method.."
for arg in args:
self.write(str(arg))
# will not work
setattr(sys.stdout.__class__,'writem',writem)

"""The above 'setattr' will give this error:
Traceback (most recent call last):
File "test_file_object.py", line 33, in ?
setattr(sys.stdout.__class__,'writem',writem)
TypeError: can't set attributes of built-in/extension type 'file'
"""

mb - Martin Bless
 
D

David MacQuigg

["Rainer Deyke said:
but only because 'sys.stdout.write' is too long to type all
the time, and never with more than one argument.

Yes, I feel it's a pity that the standard write method of file objects
doesn't take multiple arguments. Would take some of the pressure.

One thing I can do since Python-2.2 is to inherit from 'file' and add
for example a 'writem' (write many, write multiple) method. This does
work.

Unfortunately it seems I can't add that 'writem' method to sys.stdout,
as the following shows.

Why do you want to do this, when it is so easy to define your own
class to do exactly what you want (as in your example below)?
Anybody any ideas?

I think Ruby has what you need. The default print method requires an
explicit "\n" on every line. To me, this makes normal code look ugly,
but your preference is valid too.

Ruby also allows you to redefine its built-in classes, so if you need
that level of flexibility, this language may be a better choice.

Lua is also a possibility, but I know even less of that language.

Python differs from other languages in that it tries to keep a common
core language that is the same for everyone, while still allowing
extensions like your example below. The arguments against providing
more flexibility (e.g. a builtin macro language) are strong. See for
example:
http://groups.google.com/[email protected]

To add a variation of the print statement to the Python language, you
would need to demonstrate a real need for the change, not just a
personal preference for leaving out the " ". Generalizing the
'sys.stdout.write()' method to include multiple arguments might be
more acceptable. If you do a PEP along these lines, I would
emphasize:
- does not break existing code
- some good examples where this would have an advantage over current
best practices. Your choice of integer arguments in the example below
is wise. Had it been strings, the current solution would be to just
put '+' between the pieces instead of ','

-- Dave
 
P

Paul Rubin

I'd really like to. But unfortunately I've discovered the weak point
in my own argumentation: a new keyword could and probably would break
existing code. Therefore I can't go for a PEP until I have a better
idea.

You could suggest adding an "attribute" to the existing keyword:

print foo,bar # print with spaces
print.n foo,bar # print without spaces

I don't care too much for this idea but it would solve your immediate
concern.
 
D

Dang Griffith

The 'print' statement is just shortcut for 'sys.stdout.write' with
some convenience features suitable for most users. If you need
something else, just define your own shortcut, don't deprecate a
statement that is exactly what most users want.

'print' is not a shortcut for 'sys.stdout.write'.
'print' is a statement. 'sys.stdout.write' is a function.
You can't define a shortcut for a statement.
--dang
 
D

Dang Griffith

You could suggest adding an "attribute" to the existing keyword:

print foo,bar # print with spaces
print.n foo,bar # print without spaces

I don't care too much for this idea but it would solve your immediate
concern.

statements/keywords don't have attributes or types.
But if they did, some of the discussion surrounding
the 'import' statement (regarding paths and literals)
or the 'def' keyword (regarding decorator/wrappers)
would have other ways to look at those problems.
--dang
 
P

Peter Maas

David said:
Ruby also allows you to redefine its built-in classes, so if you need
that level of flexibility, this language may be a better choice.

Martin's redefined class does what he wants but sys.stdout is an
instance of file. All he has to do is close the predefined stdout
and open it again:

sys.stdout.close()
sys.stdout = MultiArgWriteFile('/dev/tty', 'a')

or whereever he wants sys.stdout to point to. Of course switching
the language on each problem is also an option. ;-)

Mit freundlichen Gruessen,

Peter Maas
 
D

David MacQuigg

'print' is not a shortcut for 'sys.stdout.write'.
'print' is a statement. 'sys.stdout.write' is a function.
You can't define a shortcut for a statement.

I'm not using the word 'shortcut' very precisely. Mark Lutz says what
I mean more clearly in Learning Python, 2nd ed. p. 143: "the print
statement ... provides a user-friendly interface to the sys.stdout
object, with bit of default formatting." I conclude from this that
'print' has no special functionality unavailable through the stdout
object, and that the proper way to change the default user-friendly
interface is to write a new one, doing just what 'print' does, but
with different defaults.

What I think is going on "under the hood" with the print statement is:

def print(*args):
for arg in args:
sys.stdout.write(arg)
sys.stdout.write(' ')
sys.stdout.write('\n')

To make a variation on this, just add or delete the extra formatting.
Of course, we need to call it something besides the keyword 'print'.

-- Dave
 
M

Mel Wilson

What I think is going on "under the hood" with the print statement is:

def print(*args):
for arg in args:
sys.stdout.write(arg)
^^^
Ahem, (str(arg))
sys.stdout.write(' ')
sys.stdout.write('\n')

To make a variation on this, just add or delete the extra formatting.
Of course, we need to call it something besides the keyword 'print'.

Regards. Mel.
 
M

Martin Bless

[Peter Maas said:
instance of file. All he has to do is close the predefined stdout
and open it again:

sys.stdout.close()
sys.stdout = MultiArgWriteFile('/dev/tty', 'a')

Telepathy? You already answered part of what I was just going to ask!

And then: Is it possible to reopen sys.stdout if the platform ist not
Unix-like?
 
P

Peter Maas

Martin said:
And then: Is it possible to reopen sys.stdout if the platform ist not
Unix-like?

Yes but e.g. Win32 does not know /dev files, so am not sure what
to substitute for /dev/tty. DOS had a "device" called CON which is
still alive in Win32 consoles (echo Hi > CON) but I have not tested
that.

Mit freundlichen Gruessen,

Peter Maas
 
S

Stephen Horne

Yes but e.g. Win32 does not know /dev files, so am not sure what
to substitute for /dev/tty. DOS had a "device" called CON which is
still alive in Win32 consoles (echo Hi > CON) but I have not tested
that.

Mit freundlichen Gruessen,

Peter Maas

Easy solution - write your extender such that it takes the original
file in the constructor...

sys.stdout = ExtendedFile (sys.stdout)


One thing, though - can't this cause problems when different modules
separately import 'sys'. Given that the new sys.stdout should be
compatible with the old one (use inheritance and just add/override the
required methods) I'm far from sure, but this approach makes me feel a
bit uneasy - I suspect a future of obscure and hard to trace bugs.
 

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,780
Messages
2,569,608
Members
45,244
Latest member
cryptotaxsoftware12

Latest Threads

Top