4

Please consider the following Python 3.x code:

class FancyWriter:    
    def write(self, string):
        print('<'+string+'>')
        return len(string)+2

def testFancyWriter():
    fw = FancyWriter()
    print("Hello World!", file=fw)
    print("How many new lines do you see here?", file=fw)
    print("And here?", file=fw)
    return

testFancyWriter()

The output looks like the following:

<Hello World!>
<
>
<How many new lines do you see here?>
<
>
<And here?>
<
>

Why are these blank lines in between?

OK - the real intention for creating something like a FancyWriter class was actually to create a writer class for Excel: I need to write out tabbed text lines into Excel cells, each line in an Excel row, and each tab-separated substring into the cells of that row. Strange thing is that in that ExcelWriter class (which has also a write() function like above, just that the call to print() is replaced by setting the cells value), a similar phenomenon occurs - there are blank rows like in the FancyWriter classes' output above! (I have the target cell moving one row below, if the last character of the incoming string was a '\n'.)

Would someone be able to explain this? What is actually happening between the lines, in a literal sense?

And what would be the 'most pythonic way' for a FancyWriter (output? file?) class with a write function to get the desired output like

<Hello World!>
<How many new lines do you see here?>
<And here?>

Thanks a lot in advance!

anjokeyo
  • 41
  • 1
  • 5

1 Answers1

2

Your "blank lines" are really your function being called with a string '\n', to handle the end of line. For example, if we change the print to

print(repr(string))

and change the hello world line to

print("Hello World!", file=fw, end="zzz")

we see

'Hello World!'
'zzz'
'How many new lines do you see here?'
'\n'
'And here?'
'\n'

Basically, print doesn't build a string and then add the end value to it, it simply passes end to the writer itself.

If you want to avoid this, you'll have to avoid print, I think, or special-case your writer to handle the case of receiving a certain (say, empty) argument, because it looks like print is going to pass end even if it's the empty string.

DSM
  • 342,061
  • 65
  • 592
  • 494
  • The `end=''` does not work, as `print` calls the writer with the empty string anyway. – Dave J Jun 14 '15 at 13:28
  • @DaveJ: yeah, I just discovered that myself. :-) Neither None, so it looks like we'll have to special-case on the writer side (or avoid `print` entirely.) – DSM Jun 14 '15 at 13:29
  • It might be best to just handle the `len(string) == 0`-case (or `string == DONTPRINT` :P) by not printing anything. – Dave J Jun 14 '15 at 13:34
  • It's as you said, DSM and Dave J, the write function is called in turns: first with the 'main' string, and then with the end string. I ended up with a toggle FancyWriter.isEndString, which initial value is False, and is not'ed in each call of the write function. If the toggle is True - so for end strings -, I only print them if they are non-white. If the toggle is False, I just print as normal. The idea of the toggle was somewhere else posted here on SO. Thank you all for your help! – anjokeyo Jun 15 '15 at 14:25