我想使用Python将打印重定向到一个.txt文件。我有一个for循环,它将打印每个.bam文件的输出,而我想将所有输出重定向到一个文件。所以我试着说:
f = open('output.txt','w')
sys.stdout = f
在我剧本的开头。但是,我在.txt文件中什么也没有得到。
我的剧本是:
#!/usr/bin/python
import os,sys
import subprocess
import glob
from os import path
f = open('output.txt','w')
sys.stdout = f
path= '/home/xxx/nearline/bamfiles'
bamfiles = glob.glob(path + '/*.bam')
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
print 'Filename:', filename
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
linelist= samtoolsin.stdout.readlines()
print 'Readlines finished!'
那么问题是什么呢?除了sys。stdout还有其他方法吗?
我需要我的结果看起来像:
Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
你可以用file参数重定向打印(在python2中有>>操作符代替)。
f = open(filename,'w')
print('whatever', file=f) # Python 3.x
print >>f, 'whatever' # Python 2.x
在大多数情况下,最好只是正常地写入文件。
f.write('whatever')
或者,如果你有几个项目想用空格写,比如print:
f.write(' '.join(('whatever', str(var2), 'etc')))
最明显的方法是打印到一个文件对象:
with open('out.txt', 'w') as f:
print('Filename:', filename, file=f) # Python 3.x
print >> f, 'Filename:', filename # Python 2.x
不过,重定向stdout对我也有用。对于像这样的一次性脚本,它可能很好:
import sys
orig_stdout = sys.stdout
f = open('out.txt', 'w')
sys.stdout = f
for i in range(2):
print('i = ', i)
sys.stdout = orig_stdout
f.close()
从Python 3.4开始,就有一个简单的上下文管理器可以在标准库中做到这一点:
from contextlib import redirect_stdout
with open('out.txt', 'w') as f:
with redirect_stdout(f):
print('data')
从shell本身向外部重定向是另一种选择,通常是更可取的:
./script.py > out.txt
其他问题:
你的脚本的第一个文件名是什么?我没有看到它被初始化。
我的第一个猜测是glob没有找到任何bamfile,因此for循环不会运行。检查文件夹是否存在,并在脚本中打印bamfiles。
同样,使用os.path.join和os.path.basename来操作路径和文件名。
在python 3中,你可以重新赋值print:
#!/usr/bin/python3
def other_fn():
#This will use the print function that's active when the function is called
print("Printing from function")
file_name = "test.txt"
with open(file_name, "w+") as f_out:
py_print = print #Need to use this to restore builtin print later, and to not induce recursion
print = lambda out_str : py_print(out_str, file=f_out)
#If you'd like, for completeness, you can include args+kwargs
print = lambda *args, **kwargs : py_print(*args, file=f_out, **kwargs)
print("Writing to %s" %(file_name))
other_fn() #Writes to file
#Must restore builtin print, or you'll get 'I/O operation on closed file'
#If you attempt to print after this block
print = py_print
print("Printing to stdout")
other_fn() #Writes to console/stdout
注意,来自other_fn的print仅切换输出,因为print在全局作用域中被重新赋值。如果在函数中赋值print, other_fn中的print通常不受影响。如果我们想影响所有的打印调用,我们可以使用global关键字:
import builtins
def other_fn():
#This will use the print function that's active when the function is called
print("Printing from function")
def main():
global print #Without this, other_fn will use builtins.print
file_name = "test.txt"
with open(file_name, "w+") as f_out:
print = lambda *args, **kwargs : builtins.print(*args, file=f_out, **kwargs)
print("Writing to %s" %(file_name))
other_fn() #Writes to file
#Must restore builtin print, or you'll get 'I/O operation on closed file'
#If you attempt to print after this block
print = builtins.print
print("Printing to stdout")
other_fn() #Writes to console/stdout
就我个人而言,我更倾向于通过将输出文件描述符烘焙到一个新函数中来避免使用print函数的要求:
file_name = "myoutput.txt"
with open(file_name, "w+") as outfile:
fprint = lambda pstring : print(pstring, file=outfile)
print("Writing to stdout")
fprint("Writing to %s" % (file_name))
不要使用打印,使用日志记录
您可以更改sys。Stdout指向文件,但这是一种相当笨拙且不灵活的处理此问题的方法。不要使用print,而是使用logging模块。
使用日志记录,您可以像打印stdout一样进行打印,也可以将输出写入文件。您甚至可以使用不同的消息级别(关键、错误、警告、信息、调试),例如,只将主要问题打印到控制台,但仍然将次要代码操作记录到文件中。
一个简单的例子
导入日志记录,获取日志记录器,并设置处理级别:
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed
如果你想打印到标准输出:
ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)
如果你也想写入一个文件(如果你只想写入一个文件,跳过最后一部分):
fh = logging.FileHandler('myLog.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)
然后,无论你在哪里使用打印,请使用记录器方法之一:
# 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')
要了解关于使用更高级日志功能的更多信息,请阅读Python文档中的优秀日志教程。