I want to redirect the print to a .txt file using python. I have a \'for\' loop, which will \'print\' the output for each of my .bam file while I want to redirect ALL these
Changing the value of sys.stdout does change the destination of all calls to print. If you use an alternative way to change the destination of print, you will get the same result.
Your bug is somewhere else:
You can redirect print with the >>
operator.
f = open(filename,'w')
print >>f, 'whatever' # Python 2.x
print('whatever', file=f) # Python 3.x
In most cases, you're better off just writing to the file normally.
f.write('whatever')
or, if you have several items you want to write with spaces between, like print
:
f.write(' '.join(('whatever', str(var2), 'etc')))
This works perfectly:
import sys
sys.stdout=open("test.txt","w")
print ("hello")
sys.stdout.close()
Now the hello will be written to the test.txt file. Make sure to close the stdout
with a close
, without it the content will not be save in the file
Python 2 or Python 3 API reference:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
The file argument must be an object with a
write(string)
method; if it is not present orNone
, sys.stdout will be used. Since printed arguments are converted to text strings,print()
cannot be used with binary mode file objects. For these, usefile.write(...)
instead.
Since file object normally contains write()
method, all you need to do is to pass a file object into its argument.
with open('file.txt', 'w') as f:
print('hello world', file=f)
with open('file.txt', 'a') as f:
print('hello world', file=f)
You may not like this answer, but I think it's the RIGHT one. Don't change your stdout destination unless it's absolutely necessary (maybe you're using a library that only outputs to stdout??? clearly not the case here).
I think as a good habit you should prepare your data ahead of time as a string, then open your file and write the whole thing at once. This is because input/output operations are the longer you have a file handle open, the more likely an error is to occur with this file (file lock error, i/o error, etc). Just doing it all in one operation leaves no question for when it might have gone wrong.
Here's an example:
out_lines = []
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
out_lines.append('Filename: %s' % filename)
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
linelist= samtoolsin.stdout.readlines()
print 'Readlines finished!'
out_lines.extend(linelist)
out_lines.append('\n')
And then when you're all done collecting your "data lines" one line per list item, you can join them with some '\n'
characters to make the whole thing outputtable; maybe even wrap your output statement in a with
block, for additional safety (will automatically close your output handle even if something goes wrong):
out_string = '\n'.join(out_lines)
out_filename = 'myfile.txt'
with open(out_filename, 'w') as outf:
outf.write(out_string)
print "YAY MY STDOUT IS UNTAINTED!!!"
However if you have lots of data to write, you could write it one piece at a time. I don't think it's relevant to your application but here's the alternative:
out_filename = 'myfile.txt'
outf = open(out_filename, 'w')
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
outf.write('Filename: %s' % filename)
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
mydata = samtoolsin.stdout.read()
outf.write(mydata)
outf.close()
print
, use logging
You can change sys.stdout
to point to a file, but this is a pretty clunky and inflexible way to handle this problem. Instead of using print
, use the logging module.
With logging
, you can print just like you would to stdout
, or you can also write the output to a file. You can even use the different message levels (critical
, error
, warning
, info
, debug
) to, for example, only print major issues to the console, but still log minor code actions to a file.
Import logging
, get the logger
, and set the processing level:
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed
If you want to print to stdout:
ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)
If you want to also write to a file (if you only want to write to a file skip the last section):
fh = logging.FileHandler('myLog.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)
Then, wherever you would use print
use one of the logger
methods:
# print(foo)
logger.debug(foo)
# print('finishing processing')
logger.info('finishing processing')
# print('Something may be wrong')
logger.warning('Something may be wrong')
# print('Something is going really bad')
logger.error('Something is going really bad')
To learn more about using more advanced logging
features, read the excellent logging tutorial in the Python docs.