Recipe2.13.Using a C-like iostream Syntax


Recipe 2.13. Using a C++-like iostream Syntax

Credit: Erik Max Francis

Problem

You like the C++ approach to I/O, based on ostreams and manipulators (special objects that cause special effects on a stream when inserted in it) and want to use it in your Python programs.

Solution

Python lets you overload operators by having your classes define special methods (i.e., methods whose names start and end with two underscores). To use << for output, as you do in C++, you just need to code an output stream class that defines the special method _ _lshift_ _:

class IOManipulator(object):     def _ _init_ _(self, function=None):         self.function = function     def do(self, output):         self.function(output) def do_endl(stream):     stream.output.write('\n')     stream.output.flush( ) endl = IOManipulator(do_endl) class OStream(object):     def _ _init_ _(self, output=None):         if output is None:             import sys             output = sys.stdout         self.output = output         self.format = '%s'     def _ _lshift_ _(self, thing):         ''' the special method which Python calls when you use the <<             operator and the left-hand operand is an OStream '''         if isinstance(thing, IOManipulator):             thing.do(self)         else:             self.output.write(self.format % thing)             self.format = '%s'         return self def example_main( ):     cout = OStream( )     cout<< "The average of " << 1 << " and " << 3 << " is " << (1+3)/2 <<endl # emits The average of 1 and 3 is 4 if _ _name_ _ == '_ _main_ _':     example_main( )

Discussion

Wrapping Python file-like objects to emulate C++ ostreams syntax is quite easy. This recipe shows how to code the insertion operator << for this purpose. The recipe also implements an IOManipulator class (as in C++) to call arbitrary functions on a stream upon insertion, and a predefined manipulator endl (guess where that name comes from) to write a newline and flush the stream.

The reason class OStream's instances hold a format attribute and reset it to the default value '%s' after each self.output.write is so that you can build devious manipulators that temporarily save formatting state on the stream object, such as:

def do_hex(stream):     stream.format = '%x' hex = IOManipulator(do_hex) cout << 23 << ' in hex is ' << hex << 23 << ', and in decimal ' << 23 << endl # emits 23 in hex is 17, and in decimal 23

Some people detest C++'s cout << something syntax, some love it. In cases such as the example given in the recipe, this syntax ends up simpler and more readable than:

print>>somewhere, "The average of %d and %d is %f\n" % (1, 3, (1+3)/2)

which is the "Python-native" alternative (looking a lot like C in this case). It depends in part on whether you're more used to C++ or to C. In any case, this recipe gives you a choice! Even if you don't end up using this particular approach, it's still interesting to see how simple operator overloading is in Python.

See Also

Library Reference and Python in a Nutshell docs on file objects and special methods such as _ _lshift_ _; Recipe 4.20 implements a Python version of C's printf function.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net