Issue of redirecting the stdout to both file and screen

Discussion in 'Python' started by =?gb2312?B?yMvR1MLkyNXKx8zs0cSjrM37vKvM7NHEsru8+7z, May 28, 2007.

  1. I wanna print the log to both the screen and file, so I simulatered a
    'tee'

    class Tee(file):

    def __init__(self, name, mode):
    file.__init__(self, name, mode)
    self.stdout = sys.stdout
    sys.stdout = self

    def __del__(self):
    sys.stdout = self.stdout
    self.close()

    def write(self, data):
    file.write(self, data)
    self.stdout.write(data)

    Tee('logfile', 'w')
    print >>sys.stdout, 'abcdefg'

    I found that it only output to the file, nothing to screen. Why?
    It seems the 'write' function was not called when I *print* something.
    =?gb2312?B?yMvR1MLkyNXKx8zs0cSjrM37vKvM7NHEsru8+7z, May 28, 2007
    #1
    1. Advertising

  2. =?gb2312?B?yMvR1MLkyNXKx8zs0cSjrM37vKvM7NHEsru8+7z

    Peter Otten Guest

    人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶ wrote:

    > I wanna print the log to both the screen and file, so I simulatered a
    > 'tee'
    >
    > class Tee(file):
    >
    > def __init__(self, name, mode):
    > file.__init__(self, name, mode)
    > self.stdout = sys.stdout
    > sys.stdout = self
    >
    > def __del__(self):
    > sys.stdout = self.stdout
    > self.close()
    >
    > def write(self, data):
    > file.write(self, data)
    > self.stdout.write(data)
    >
    > Tee('logfile', 'w')
    > print >>sys.stdout, 'abcdefg'
    >
    > I found that it only output to the file, nothing to screen. Why?
    > It seems the 'write' function was not called when I *print* something.


    There are places in the C code of Python that do the equivalent of

    if isinstance(file_like_object, file):
    file.write(file_like_object, text)
    else:
    file_like_object.write(text)

    Therefore you can't safely inherit from file. The workaround is to make your
    own file-like object; yours would become

    class Tee(object):
    def __init__(self, name, mode):
    self.file = open(name, mode)
    self.stdout = sys.stdout
    sys.stdout = self
    def __del__(self):
    sys.stdout = self.stdout
    self.file.close()
    def write(self, data):
    self.file.write(data)
    self.stdout.write(data)

    Peter
    Peter Otten, May 28, 2007
    #2
    1. Advertising

  3. En Mon, 28 May 2007 06:17:39 -0300, 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶
    <> escribió:

    > I wanna print the log to both the screen and file, so I simulatered a
    > 'tee'
    >
    > class Tee(file):
    >
    > def __init__(self, name, mode):
    > file.__init__(self, name, mode)
    > self.stdout = sys.stdout
    > sys.stdout = self
    >
    > def __del__(self):
    > sys.stdout = self.stdout
    > self.close()
    >
    > def write(self, data):
    > file.write(self, data)
    > self.stdout.write(data)
    >
    > Tee('logfile', 'w')
    > print >>sys.stdout, 'abcdefg'
    >
    > I found that it only output to the file, nothing to screen. Why?
    > It seems the 'write' function was not called when I *print* something.


    You create a Tee instance and it is immediately garbage collected. I'd
    restore sys.stdout on Tee.close, not __del__ (you forgot to call the
    inherited __del__ method, btw).
    Mmm, doesn't work. I think there is an optimization somewhere: if it looks
    like a real file object, it uses the original file write method, not yours.
    The trick would be to use an object that does NOT inherit from file:

    import sys
    class TeeNoFile(object):
    def __init__(self, name, mode):
    self.file = open(name, mode)
    self.stdout = sys.stdout
    sys.stdout = self
    def close(self):
    if self.stdout is not None:
    sys.stdout = self.stdout
    self.stdout = None
    if self.file is not None:
    self.file.close()
    self.file = None
    def write(self, data):
    self.file.write(data)
    self.stdout.write(data)
    def flush(self):
    self.file.flush()
    self.stdout.flush()
    def __del__(self):
    self.close()

    tee=TeeNoFile('logfile', 'w')
    print 'abcdefg'
    print 'another line'
    tee.close()
    print 'screen only'
    del tee # should do nothing

    --
    Gabriel Genellina
    Gabriel Genellina, May 28, 2007
    #3
  4. =?gb2312?B?yMvR1MLkyNXKx8zs0cSjrM37vKvM7NHEsru8+7z

    Peter Otten Guest

    Gabriel Genellina wrote:

    > En Mon, 28 May 2007 06:17:39 -0300, ???????????????
    > <> escribió:
    >
    >> I wanna print the log to both the screen and file, so I simulatered a
    >> 'tee'
    >>
    >> class Tee(file):
    >>
    >> def __init__(self, name, mode):
    >> file.__init__(self, name, mode)
    >> self.stdout = sys.stdout
    >> sys.stdout = self
    >>
    >> def __del__(self):
    >> sys.stdout = self.stdout
    >> self.close()
    >>
    >> def write(self, data):
    >> file.write(self, data)
    >> self.stdout.write(data)
    >>
    >> Tee('logfile', 'w')
    >> print >>sys.stdout, 'abcdefg'
    >>
    >> I found that it only output to the file, nothing to screen. Why?
    >> It seems the 'write' function was not called when I *print* something.

    >
    > You create a Tee instance and it is immediately garbage collected.


    It is not garbage collected until the next assignment to sys.stdout.

    Peter
    Peter Otten, May 28, 2007
    #4
  5. En Mon, 28 May 2007 09:10:40 -0300, Peter Otten <>
    escribió:

    > Gabriel Genellina wrote:
    >
    >> En Mon, 28 May 2007 06:17:39 -0300, ???????????????
    >> <> escribió:
    >>
    >>> def __init__(self, name, mode):
    >>> file.__init__(self, name, mode)
    >>> self.stdout = sys.stdout
    >>> sys.stdout = self
    >>>
    >>> Tee('logfile', 'w')
    >>> print >>sys.stdout, 'abcdefg'
    >>>
    >>> I found that it only output to the file, nothing to screen. Why?
    >>> It seems the 'write' function was not called when I *print* something.

    >>
    >> You create a Tee instance and it is immediately garbage collected.

    >
    > It is not garbage collected until the next assignment to sys.stdout.


    Yes, sorry, this was my first guess. Later I discovered the real reason
    -you pointed it too-, I should have removed the whole first paragraph on
    my reply.

    --
    Gabriel Genellina
    Gabriel Genellina, May 28, 2007
    #5
  6. I see. Many thanks to you!
    =?gb2312?B?yMvR1MLkyNXKx8zs0cSjrM37vKvM7NHEsru8+7z, May 29, 2007
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Elad
    Replies:
    0
    Views:
    411
  2. SamG
    Replies:
    10
    Views:
    424
  3. ABCL
    Replies:
    0
    Views:
    546
  4. comp.lang.ruby
    Replies:
    4
    Views:
    279
    Gary Wright
    Jan 11, 2010
  5. it_says_BALLS_on_your forehead
    Replies:
    2
    Views:
    265
    Joe Smith
    Jan 10, 2006
Loading...

Share This Page