Credit: Jürgen Hermann
You want functionality
similar to that of the print
statement on a file
object that is not necessarily standard output, and you want to
access this functionality in an object-oriented manner.
Statement print
is quite handy, but we can emulate
(and optionally tweak) its semantics with nicer, object-oriented
syntax by writing a suitable class:
class PrintDecorator: """ Add print-like methods to any writable file-like object. """ def _ _init_ _(self, stream, do_softspace=1): """ Store away the stream for later use. """ self.stream = stream self.do_softspace = do_softspace self.softspace = 0 def Print(self, *args, **kw): """ Print all arguments as strings, separated by spaces. Take an optional "delim" keyword parameter to change the delimiting character and an optional "linend" keyword parameter to insert a line-termination string. Ignores unknown keyword parameters for simplicity. """ delim = kw.get('delim', ' ') linend = kw.get('linend', '') if self.do_softspace and self.softspace and args: start = delim else: start = '' self.stream.write(start + delim.join(map(str, args)) + linend) self.softspace = not linend def PrintLn(self, *args, **kw): """ Just like self.Print( ), but linend defaults to line-feed. """ kw.setdefault('linend',' ') self.Print(*args, **kw) if _ _name_ _ == '_ _main_ _': # Here's how you use this: import sys out = PrintDecorator(sys.stdout) out.PrintLn(1, "+", 1, "is", 1+1) out.Print("Words", "Smashed", "Together", delim='') out.PrintLn( )
This recipe shows how to decorate objects with new
functions, specifically by decorating an arbitrary writable stream
(file-like object opened for writing) with two methods that work like
the built-in print
statement.
The
Print
method takes any number of positional arguments, converts them to
strings (via the map
and str
built-ins), joins these strings with the given
delim
, then finally writes the resulting string to
the stream. An optional linend
, the empty string
by default, allows line termination.
The PrintLn
method delegates to
Print
, changing the default for the
linend
argument to '
'
. Other
ways of sharing common code between Print
and
PrintLn
run into difficulties—for example,
when delim
is nonwhitespace or on multitasking
environments where printing operations need to be atomic (a single
call to the stream’s method write
per call to the decorator’s Print
or PrintLn
methods).
Softspace functionality is also provided to emulate the
print
statement’s ability to
avoid inserting a useless trailing space if a newline should
immediately follow. This seems simple, and it’s
definitely useful, but it can be tricky to implement. Furthermore,
this wrapper supports softspace functionality independently of the
decorated stream’s support for setting and getting
the softspace
attribute. Softspace behavior can,
however, appear somewhat strange if successive
Print
calls use different delim
strings. The softspace functionality can be turned off at
instantiation time.
The code uses Python 2.x syntax (string methods, new-style argument
passing), but it can be easily ported to Python 1.5.2 (if necessary)
by using apply
for function calling and the
string
module instead of string methods.