Search code examples
pythonsubprocess

Why does `print foo.communicate()[0]` differ from `print foo.communicate()`"


Here is the situation:

I've got a command I'm running:

import subprocess
foo = subprocess.Popen('ls /', shell=True, stdout=subprocess.PIPE,\
stderr=subprocess.STDOUT)

Pretty basic, right? And I've figured out that I can do stuff with the output with .communicate(), like this:

print foo.communicate()

Which works great and produces the output that the documentation for subprocess.communicate suggests it should, a tuple:

('bin\nboot\ncdrom\n[...stuff redacted for brevity...]tmp\nusr\nvar\nvmlinuz\n', None)

Notice the \n newlines in there. And I've discovered that just asking for the first element of the tuple produces output with newlines, like this:

>>> print foo.communicate()[0]
bin
boot
cdrom
[...stuff redacted for brevity...]
tmp
usr
var
vmlinuz

But what I don't understand is WHY printing with just the first element produces the newlines. Don't get me wrong, it is great, and I'm glad I can do it without a loop, but I'd like to understand what is going on.


Solution

  • In Python when you call something like print obj, you're actually calling the __str__ on the object and then interpreting the result as a string.

    So for example say you have:

          >>> a = ('foo\nbar', '5')
          >>> print a
          ('foo\nbar', '5')
    

    As you've noticed. But if you do something like:

          >>> class mytuple(tuple):
                  def __str__(self):
                      return ''.join(self)
          >>> b = mytuple(a)
          >>> print b
          foo
          bar5
    

    This subclass of the tuple type goes beyond the standard __str__ and builds a string composed out the string representations of its constituent parts.

    The reason this isn't done in the general case is that you never know what objects could be inserted in a tuple, or list - not all objects have string-able representations.