Again: Please hear my plea: print without softspace

Stephen Horne steve at ninereeds.fsnet.co.uk
Mon Mar 1 20:33:13 EST 2004


On Mon, 01 Mar 2004 21:42:21 GMT, "Rainer Deyke" <rainerd at eldwood.com>
wrote:

>Josiah Carlson wrote:
>> 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.

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] != ' ') :
          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=""



-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk



More information about the Python-list mailing list