【问题标题】:Python output on both console and file控制台和文件上的 Python 输出
【发布时间】:2014-08-03 23:43:08
【问题描述】:

我正在编写代码来分析 PDF 文件。我想在控制台上显示输出以及在文件中保存输出的副本,我使用此代码将输出保存在文件中:

import sys
sys.stdout = open('C:\\users\\Suleiman JK\\Desktop\\file.txt',"w")
print "test"

但我是否也可以将输出显示到控制台但不使用类,因为我不擅长使用它们?

【问题讨论】:

  • 您可以使用f.write(data) 将输出存储在一个文件中,然后使用print(data) 打印到控制台。我不明白问题中的类参考。
  • Python logging 模块来救援!
  • @Llopis 我的意思是我知道如何使用类。如果我想在上面的示例中使用它,我该如何使用 write
  • 使用 X 类的方法来做到这一点。 X.write(): ..... 其中 .... 是您发布的代码或其任何变体。虽然我不知道您为什么要这样做,但日志记录包也可以解决您的问题。

标签: python file console output


【解决方案1】:

您可以创建一个同时打印到控制台和文件的函数。您可以通过切换标准输出来做到这一点,例如像这样:

def print_both(file, *args):
    temp = sys.stdout #assign console output to a variable
    print ' '.join([str(arg) for arg in args]) 
    sys.stdout = file 
    print ' '.join([str(arg) for arg in args])
    sys.stdout = temp #set stdout back to console output

或使用文件写入方法(我建议使用此方法,除非您必须使用标准输出)

def print_both(file, *args):
    toprint = ' '.join([str(arg) for arg in args])
    print toprint
    file.write(toprint)

注意:

  1. 传递给函数的文件参数必须在函数外部打开(例如在程序开始时)并在函数外部关闭(例如在程序结束时)。您应该以附加模式打开它。
  2. 将 *args 传递给函数允许您以与打印函数相同的方式传递参数。所以你将参数传递给 print...

...像这样:

print_both(open_file_variable, 'pass arguments as if it is', 'print!', 1, '!')

否则,您必须将所有内容都转换为单个参数,即单个字符串。它看起来像这样:

 print_both(open_file_variable, 'you should concatenate'+str(4334654)+'arguments together')

我仍然建议你学会正确使用类,你会从中受益匪浅。希望这会有所帮助。

【讨论】:

  • 如果我的代码中有很多“打印”命令怎么办?
  • 而不是 print 使用 print_both 例如print_both(file, 'print stuff'); print_both(file, 'print something else')
【解决方案2】:

(此答案使用 Python 3,如果您更喜欢 Python 2,则必须对其进行调整。)

首先导入 Python logging 包(以及用于访问标准输出流的 sys):

import logging
import sys

在您的入口点,set up a handler 用于标准输出流和您的输出文件:

targets = logging.StreamHandler(sys.stdout), logging.FileHandler('test.log')

configure the logging package 只输出不带日志级别的消息:

logging.basicConfig(format='%(message)s', level=logging.INFO, handlers=targets)

现在你可以使用它了:

>>> logging.info('testing the logging system')
testing the logging system
>>> logging.info('second message')
second message
>>> print(*open('test.log'), sep='')
testing the logging system
second message

【讨论】:

    【解决方案3】:

    sys.stdout 可以指向任何具有 write 方法的对象,因此您可以创建一个同时写入文件和控制台的类。

    import sys
    
    class LoggingPrinter:
        def __init__(self, filename):
            self.out_file = open(filename, "w")
            self.old_stdout = sys.stdout
            #this object will take over `stdout`'s job
            sys.stdout = self
        #executed when the user does a `print`
        def write(self, text): 
            self.old_stdout.write(text)
            self.out_file.write(text)
        #executed when `with` block begins
        def __enter__(self): 
            return self
        #executed when `with` block ends
        def __exit__(self, type, value, traceback): 
            #we don't want to log anymore. Restore the original stdout object.
            sys.stdout = self.old_stdout
    
    print "Entering section of program that will be logged."
    with LoggingPrinter("result.txt"):
        print "I've got a lovely bunch of coconuts."
    print "Exiting logged section of program."
    

    结果:

    控制台:

    Entering section of program that will be logged.
    I've got a lovely bunch of coconuts.
    Exiting logged section of program.
    

    结果.txt:

    I've got a lovely bunch of coconuts.
    

    在某些情况下,此方法可能比codesparkle 更可取,因为您不必将所有现有的prints 替换为logging.info。只需将您想要登录的所有内容放入 with 块中即可。

    【讨论】:

      【解决方案4】:

      我懒得写函数,所以当我需要打印到控制台和文件时,我写了这个快速且(不是那么)脏的代码:

      import sys
      ...
      with open('myreport.txt', 'w') as f:
          for out in [sys.stdout, f]:
              print('some data', file=out)
              print('some mre data', file=out)
      

      【讨论】: