Please hear my plea: print without softspace

M

Martin Bless

Why can't we have an additional 'print' statement, that behaves
exactly like 'print' but doesn't insert that damn blank between two
arguments?

Could be called 'printn' or 'prin1' or 'prinn' anything similar you
like.

Would make my life so much easier. Often I start with a nice and short
print statement, then there happen to be more arguments and neat
formatting becomes more important and as a result I find myself
rewriting the code over and over again just to cope with those blanks
I'm forced to take into account.

Coding would be easier: If there are more arguments to print, it's
just the argument list that grows. If you need a blank then add one.
But you don't have to rewrite your arguments into expressions which
can be tedious and isn't efficient anyway if its an extra operation
just to get rid of those blanks.

What do you think?

Martin
 
C

Carmine Noviello

def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?
 
R

Robin Becker

def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?
Give stdout a good hiding :)

##############
class hidesoftspace:
def __init__(self,fobj):
self.__dict__['_fobj'] = fobj
fobj.softspace = False
def __getattr__(self,a):
if a=='softspace': return False
return getattr(self._fobj,a)
def __setattr__(self,a,v):
if a=='softspace': return
setattr(self._fobj,a,v)

import sys
print 'before hiding',1,2,3,4
sys.stdout=hidesoftspace(sys.stdout)
print 'after hiding',1,2,3,4
##############
results in

before hiding 1 2 3 4
after hiding1234
 
A

Andrei

Martin Bless wrote on Sat, 28 Feb 2004 11:56:55 GMT:
Why can't we have an additional 'print' statement, that behaves
exactly like 'print' but doesn't insert that damn blank between two
arguments?

Could be called 'printn' or 'prin1' or 'prinn' anything similar you
like.
What do you think?

In these cases I tend to use string formatting, e.g.:

print '%s-%s-%s' % (1,2,3)

As others have already pointed out, there are several other ways too, so
making a new keyword for this doesn't seem very useful.

--
Yours,

Andrei

=====
Real contact info (decode with rot13):
(e-mail address removed). Fcnz-serr! Cyrnfr qb abg hfr va choyvp cbfgf. V ernq
gur yvfg, fb gurer'f ab arrq gb PP.
 
V

Valentino Volonghi aka Dialtone

In data Sat, 28 Feb 2004 12:01:40 +0000 (UTC), Carmine Noviello ha
scritto:
def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?

I would use this instead:

def pprint(*args):
txt = []
for a in args:
txt.append(a)
print ''.join(txt)

which is a lot faster :)
 
M

Mel Wilson

In data Sat, 28 Feb 2004 12:01:40 +0000 (UTC), Carmine Noviello ha
scritto:
def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?

I would use this instead:

def pprint(*args):
txt = []
for a in args:
txt.append(a)
print ''.join(txt)

which is a lot faster :)

Sorry.

Python 2.3 (#46, Jul 29 2003, 18:54:32) [MSC v.1200 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information..... txt = []
.... for a in args:
.... txt.append(a)
.... print ''.join(txt)
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 5, in pprint
TypeError: sequence item 0: expected string, int found



def pprint (*args):
print ''.join ([str(x) for x in args])



Regards. Mel.
 
K

kosh

In data Sat, 28 Feb 2004 12:01:40 +0000 (UTC), Carmine Noviello ha

scritto:
def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?

I would use this instead:

def pprint(*args):
txt = []
for a in args:
txt.append(a)
print ''.join(txt)

which is a lot faster :)

why not?

def pprint(*args):
print ''.join(args)

if you want it to be more robust you could do

def pprint(*args):
print ''.join(map(str,args))

That would try and convert all the items to a string first before joining
them.
 
N

Nick Patavalis

##############
class hidesoftspace:
def __init__(self,fobj):
self.__dict__['_fobj'] = fobj
fobj.softspace = False
def __getattr__(self,a):
if a=='softspace': return False
return getattr(self._fobj,a)
def __setattr__(self,a,v):
if a=='softspace': return
setattr(self._fobj,a,v)

import sys
print 'before hiding',1,2,3,4
sys.stdout=hidesoftspace(sys.stdout)
print 'after hiding',1,2,3,4
##############

Would you perhaps care to comment a bit more, or provide a pointer to
some docs? It seems that there is a "softspace" atribute in the
sys.stdout file object, and that this attribute gets set by the print
statement itself. With your clever trick you make it imposible for
someone to set this attribute to anything else but "False". What are
the exact semantics behind this?

I tried this:

import sys
print sys.stdout.softspace
0
print "test:", 1, 2, 3, sys.stdout.softspace
test: 1 2 3 1
print sys.stdout.softspace
0

Which seems to support my explanation, but what exactly are the
semantics of "softspace"?

Thanks
/npat
 
V

Valentino Volonghi aka Dialtone

In data Sat, 28 Feb 2004 09:44:57 -0700, kosh ha scritto:
why not?

def pprint(*args):
print ''.join(args)

if you want it to be more robust you could do

def pprint(*args):
print ''.join(map(str,args))

That would try and convert all the items to a string first before joining
them.

I would have used the list comprehension solution that Mel Wilson posted
but I was in a hurry and wrote wrong code...

Actually I don't like map() and I always try to use LC as much as
possible, I think they are a lot more readable.
 
R

Robin Becker

Nick Patavalis said:
##############
class hidesoftspace:
def __init__(self,fobj):
self.__dict__['_fobj'] = fobj
fobj.softspace = False
def __getattr__(self,a):
if a=='softspace': return False
return getattr(self._fobj,a)
def __setattr__(self,a,v):
if a=='softspace': return
setattr(self._fobj,a,v)

import sys
print 'before hiding',1,2,3,4
sys.stdout=hidesoftspace(sys.stdout)
print 'after hiding',1,2,3,4
##############


Would you perhaps care to comment a bit more, or provide a pointer to
some docs? It seems that there is a "softspace" atribute in the
sys.stdout file object, and that this attribute gets set by the print
statement itself. With your clever trick you make it imposible for
someone to set this attribute to anything else but "False". What are
the exact semantics behind this?
I tried this:

import sys
print sys.stdout.softspace
0
print "test:", 1, 2, 3, sys.stdout.softspace
test: 1 2 3 1
print sys.stdout.softspace
0

Which seems to support my explanation, but what exactly are the
semantics of "softspace"?

Thanks
/npat

OK I'll try. I believe softspace is a boolean attribute of the standard
file class which is used by print to indicate that a space should be
inserted in the stream before the next item. Logically it should always
be false at the beginning of a print sequence and true after the print
of an item.

You have to be careful testing this as prints at the prompt don't behave
properly ie you always get a linefeed in the command terminal.

try
from sys import stdout
print stdout.softspace,stdout.softspace,;print stdout.softspace

should give

0 1 1

my class just ensures that a wrapped (warped :)) file will never have
its softspace set to true and thus we won't get the extra spaces; in
short print always thinks the wrapped file is at the start of a print
sequence.
-softspaced in the head-ly yrs-
Robin Becker
 
K

kosh

In data Sat, 28 Feb 2004 09:44:57 -0700, kosh ha scritto:

I would have used the list comprehension solution that Mel Wilson posted
but I was in a hurry and wrote wrong code...

Actually I don't like map() and I always try to use LC as much as
possible, I think they are a lot more readable.

I use map, reduce, filter etc pretty rarely but I think in this case it is a
very simple way to say what I mean there. I just want str called on every
element in args and have a list returned with that result.

I use list comps a lot in other places but things like map do have their
place.
 
P

Paul Rubin

Carmine Noviello said:
def pprint(*args):
txt = ""
for a in args:
txt += str(a)
print txt

Is it ok?

import sys
def pprint(*args):
for a in args:
sys.stdout.write(a)
 
T

Terry Reedy

Martin Bless said:
Why can't we have an additional 'print' statement, that behaves
exactly like 'print' but doesn't insert that damn blank between two
arguments? ....
What do you think?

For exact control of output, use file.write(string).
print is a convenient wrapper for casual output to stdout,
especially with the interactive console.
Or write your own wrapper for custom default formating.

Terry J. Reedy
 
D

Dennis Lee Bieber

Why can't we have an additional 'print' statement, that behaves
exactly like 'print' but doesn't insert that damn blank between two
arguments?

Because we'd then have newbies complaining because they can't
tell different outputs apart when they use the wrong "print" statement
Would make my life so much easier. Often I start with a nice and short
said:
can be tedious and isn't efficient anyway if its an extra operation
just to get rid of those blanks.

What do you think?
/I/ think "print" should be reserved for quick and simple,
interactive prompting style, I/O operations, and anything that may
require custom, exact, formatting should be performed using
sys.stdout.write() and related... possibly with dedicated
functions/classes/modules (a report writer, say)


--
 
M

Martin Bless

[Andrei said:
In these cases I tend to use string formatting, e.g.:

print '%s-%s-%s' % (1,2,3)

As others have already pointed out, there are several other ways too, so
making a new keyword for this doesn't seem very useful.

That's exactly the point I'm trying to make: I think this new keyword
*would* be extremely useful.

The general advice I received so far is: "roll your own writer object,
create a wrapper, do those string calculations yourself, then hand the
ready to print output to 'print' or some 'write' method. 'print'
isn't good enough for sophisticated use, there are many ways to format
your output correctly..."

I *know* there are many ways. The point is: many of these
"workarounds" only come into play because there *is no* built in
variant of 'print' that doesn't emit blanks.

Advocating the 'print statement':

Let's remember:

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

- Obviously it *is* an important language feature: it even has its own
keyword.
- It's easy to use and *scalable* (no parentheses, variable number of
arguments).
- readable: pure list of arguments.
- Its efficient, since it has its built in ways of transforming
expressions to output strings, processing one by one. No need to join
those parts first.
- As a language feature it's well documented.
- 'print statements' stand for themselves and are highly expressive
and self documenting. Understanding, copying and pasting relies less
on context.

In one word: Looks like a very pythonic feature to me. Very
attractive.

And I'd simply like to benefit from all of these advantages. 99% seem
to be ok and because of 1% bad we can't use it to the full.

Aside: And there even must have been a time where 'print' has been
considered important enough to fight a long battle about introducing
the "chevron" form ('>>')...

Don't panic:

Of course I'm not saying we should change the existing behaviour of
'print' in any way.

But:

On the other hand: introducing a new keyword like 'printn' or 'prin0'

- wouldn't break any existing code
- wouldn't introduce a change of language structure
- could be documented within a few sentences ("... behaves like
'print' but does not insert blanks ...")
- and my suspicion is that the implentation in C isn't much of a
problem.

It's just like having a variant of something we allready have with
slightly different semantics. And that's ok and exactly what we want.
And it's no problem because we'd have a unique new name for it.

As far as I can see there's much benefit and little costs.

Ok, then back to where I startet. Let me asked again:

"Can we have an additional 'print' statement, that behaves exactly
like 'print' but doesn't insert blanks between arguments?"

curious,

Martin
 
R

rzed

(e-mail address removed) (Martin Bless) wrote in


[...]
Ok, then back to where I startet. Let me asked again:

"Can we have an additional 'print' statement, that behaves
exactly like 'print' but doesn't insert blanks between
arguments?"

Probably not.

I've wondered, though, whether there couldn't be a different
character instead of a ',' to alter the behavior of print. Maybe a
trailing '+' to indicate that what follows is to concatenate
directly.

And yet I've been able to work around that little annoyance; it's not
that there is no way to format output the way you want.
 
J

Josiah Carlson

I've wondered, though, whether there couldn't be a different
character instead of a ',' to alter the behavior of print. Maybe a
trailing '+' to indicate that what follows is to concatenate
directly.

And yet I've been able to work around that little annoyance; it's not
that there is no way to format output the way you want.


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.

The right thing to do (if it were to happen at all) is to make
fileobject.softspace "sticky" under some condition, perhaps after a call
to fileobject.SetSoftSpace(False) (which doesn't currently exist).

- Josiah
 
R

Rainer Deyke

Josiah said:
The right thing to do (if it were to happen at all) is to make
fileobject.softspace "sticky" under some condition, perhaps after a
call to fileobject.SetSoftSpace(False) (which doesn't currently
exist).

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.
 
S

Stephen Horne

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.

IMO, this is a job for bound methods...

import sys
stdwrite = sys.stdout.write
stdwriteln = sys.stdout.writelines

stdwriteln (["Hello ", "world\n"])


Of course, everyone wants something slightly different from their
default I/O stuff. One mans useful shortcut is another mans irritant
that he's constantly having to work around.


A simple formatting utility class is sometimes useful. After all,
formatting isn't just about where the spaces are. Word-wrapping,
indentation levels for paragraphs, bullet points and more can all make
life easy when generating complex console output. I even once
supported simple tables in a text mode output formatter, though not in
Python.

I just hacked the following together, if anyone is interested - it
definitely is not ready for real use, but it might be a useful start
for someone. The constructor optionally takes a callable object, used
to write each line, and a line length. The 'begin' and 'end' methods
do indented blocks, bullets etc. The main output methods are 'write',
'writeall' and 'writeln'.

'writeall' takes a single list parameter, converts every item in the
list using the 'str' function, and outputs each in turn.

'write' uses multiple parameters instead of a single list parameter.

'writeln' is like 'write', but ends the paragraph automatically. I'm
not sure where I got the 'ln' suffix from - either Pascal or Modula 2,
probably. Probably a bad name here, but what the hell.

'para' ends the current paragraph without writing more text.

'begin' normally takes a single string with the indent spaces and
possibly the bullet character. You might use " " for a simple indent,
for instance, or " * " for a bullet point. It can make an all-space
version for follow-on lines itself, but if you want something
different you can override it.

#
# Simple text-mode output formatter
#

import sys
import string

class Formatter :
target = sys.stdout.write
indent = ""
nxtindent = ""
curindent = None
indentstk = []
width = 80
pending = ""
separator = ""
terminator = "\n"

def __init__ (self,
target = sys.stdout.write,
width = 80 ) :
self.target = target
self.width = width

def begin (self, indent=" ", nxtindent=None) :
self.para ()
self.indentstk.append ((self.indent, self.nxtindent))
self.indent = self.nxtindent + indent

if nxtindent == None :
self.nxtindent += " " * len (indent)
else :
self.nxtindent += nxtindent

def end (self) :
self.para ()
self.indent = self.indentstk [-1] [0]
self.nxtindent = self.indentstk [-1] [1]
self.indentstk = self.indentstk [:-1]

def set_modifiers (self, separator = None, terminator = None) :
if separator != None :
self.separator = seperator

if terminator != None :
self.terminator = terminator

def write (self, *strings) :
self.writeall (strings)

def writeall (self, strings) :
t1 = string.join ([str (i) for i in strings], self.separator)

i = t1.find ("\n")

while i >= 0 :
self.pending += t1 [:i]
t1 = t1 [i+1:]
self.flush (True)
self.target ("\n")
i = t1.find ("\n")

self.pending += t1
self.flush (False)

def writeln (self, *strings) :
t1 = string.join ([str (i) for i in strings], self.separator) +
self.terminator

i = t1.find ("\n")

while i >= 0 :
self.pending += t1 [:i]
t1 = t1 [i+1:]
self.flush (True)
self.target ("\n")
i = t1.find ("\n")

self.pending += t1
self.flush (False)

def para (self) :
if self.pending != "" :
self.flush (True)
self.target ("\n")

def flush (self, force) :
if self.pending != "" :
if self.curindent == None :
self.curindent = self.indent

xwidth = self.width - len (self.indent)

while len(self.pending) >= xwidth :
i = xwidth - 1
while (i > 1) and (self.pending != ' ') :
i -= 1
self.target (self.curindent+string.rstrip (self.pending
[:i])+"\n")
self.curindent = self.nxtindent
self.pending=string.lstrip (self.pending [i:])

if force and (len (self.pending) > 0) :
self.target (self.curindent+string.rstrip (self.pending)+"\n")
self.curindent = None
self.pending=""
 
R

rzed

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.

The right thing to do (if it were to happen at all) is to make
fileobject.softspace "sticky" under some condition, perhaps
after a call to fileobject.SetSoftSpace(False) (which doesn't
currently exist).

I'm not sure I agree with this entirely. The comma following a
print statement is a sort of magic syntax as it is; it changes the
behavior of the unadorned print statement in a way that has very
little to do with any syntactical meaning a comma would normally
have. The idle thought I mentioned above would just use a different
symbol to alter the behavior of print in a slightly different
fashion. What I actually had in mind, adapting your example, was
something a little different:
print "hello" +
print "nwheels" #-> "hellonwheels"

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.

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.
 

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,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top