开发者

pythons 'print' statement doesn't call the .write() method?

开发者 https://www.devze.com 2023-03-27 09:54 出处:网络
I thought the print statement just called the .write() method on the sys.stdout (by default) object. but having written a subclass like this:

I thought the print statement just called the .write() method on the sys.stdout (by default) object.

but having written a subclass like this:

import time

cla开发者_运维技巧ss logfile(file):
    def __init__(self, *args, **kwargs):
        file.__init__(self, *args, **kwargs)

    def write(self, logstr):
        if logstr[-1] != '\n': logstr += '\n'
        super(logfile, self).write(time.strftime('%D-%T ') + str(logstr))

It seems to work if I create a logfile object and call the write method, but when trying to change the sys.stdout object to an instance of the logfile it appears as though print isn't calling write. Maybe writelines?

Using this:

#!/usr/bin/python

from myfile import logfile
import sys

sys.stdout = logfile('somefile', 'w')

print 'this is a test'
sys.stdout.write('this is another test')

My output file 'somefile' contains:

this is a test
08/10/11-16:59:47 this is another test

You can see the first line in the output file is what I tried to print and the second line is what was used in sys.stdout.write

I thought print just called the write method- clearly I'm missing something basic.


Apparently this is an limitation of the implementation of Python 2 where print is a statement rather than an expression with side-effects (as it is in Python 3).

I rewrote the code to something that works in Python 3:

from io import FileIO
import time

class logfile(FileIO):
  def __init__(self, *args, **kwargs):
    FileIO.__init__(self, *args, **kwargs)

  def write(self, logstr):
    if logstr[-1] == '\n': logstr = logstr[:-1]
    super(logfile, self).write(bytes(time.strftime('%D-%T ') + str(logstr), 'UTF-8'))

import sys

sys.stdout = logfile('somefile', 'w')

print("This is a test")
sys.stdout.write('this is another test')

As far as I know there is no way to create the same behaviour in Python 2.

I also tried using from __future__ import print_function but that made no difference.


If you put the file in an instance variable, it seems to work.

import time

class logfile(object):
    def __init__(self, *args, **kwargs):
        self.f = file(*args, **kwargs)
    def write(self, logstr):
        if logstr[-1] != '\n': logstr += '\n'
        self.f.write(time.strftime('%D-%T ') + str(logstr))

Unfortunately it logs extra empty lines, here is one solution (print '2', '3', '4' writes 3 entries):

class logfile(object):
    def __init__(self, *args, **kwargs):
        self.f = file(*args, **kwargs)
        self.c = False
    def write(self, logstr):
        self.c = not self.c
        if logstr[-1] != '\n': logstr += '\n'
        if self.c:
            self.f.write(time.strftime('%D-%T ') + str(logstr))

This one logs full lines (note: print "4\n", "5" is still 2 loglines):

class logfile(object):
    def __init__(self, *args, **kwargs):
        self.f = file(*args, **kwargs)
        self.newline = True
    def write(self, logstr):
        if self.newline:
            self.f.write(time.strftime('%D-%T '))
        self.f.write(logstr)
        self.newline = logstr[-1] == '\n'

Does anybody know how to handle full print statements in 1 loglines?


This article explains your problem. Basically if sys.stdout is a subclass of file then print bypasses sys.stdout.write and writes directly to sys.stdout.fd.

The solution to your problem is to use composition instead of subclassing file.

0

精彩评论

暂无评论...
验证码 换一张
取 消