Recipe 2.13. Using a C++-like iostream SyntaxCredit: Erik Max Francis ProblemYou 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. SolutionPython 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( ) DiscussionWrapping 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 AlsoLibrary 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. |