2012-02-17 83 views
19

我发现一些在线代码通常可用,但我想在同一个程序中多次使用它(将不同的东西写入不同的文件,同时仍然打印到屏幕上整个时间)。打印到屏幕并同时写入文件

也就是说,当它关闭时,我认为sys.stdout关闭了,所以打印并再次使用这个类失败。我试图重新导入sys和其他愚蠢的东西,但我无法让它工作。

这里的网站,并且代码 groups.google.com/group/comp.lang.python/browse_thread/thread/d25a9f5608e473af/

import sys 

class MyWriter: 

    def __init__(self, stdout, filename): 
     self.stdout = stdout 
     self.logfile = file(filename, 'a') 

    def write(self, text): 
     self.stdout.write(text) 
     self.logfile.write(text) 

    def close(self): 
     self.stdout.close() 
     self.logfile.close() 

writer = MyWriter(sys.stdout, 'log.txt') 
sys.stdout = writer 

print 'test' 
+0

何时关闭?我没有看到任何关闭。 – 2012-02-17 01:36:24

+0

你应该接受答案,真的 – gt6989b 2015-02-11 23:59:40

回答

83

您正在尝试重现Python标准库所做的非常好的事情;请检查logging module

使用此模块,您可以按照您想要的方式进行操作,但操作更加简单,标准和可扩展。您可以按以下步骤操作(本例中是从logging cookbook复制/粘贴):

Let’s say you want to log to console and file with different message formats and in differing circumstances. Say you want to log messages with levels of DEBUG and higher to file, and those messages at level INFO and higher to the console. Let’s also assume that the file should contain timestamps, but the console messages should not. Here’s how you can achieve this:

import logging 

# set up logging to file - see previous section for more details 
logging.basicConfig(level=logging.DEBUG, 
        format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', 
        datefmt='%m-%d %H:%M', 
        filename='/temp/myapp.log', 
        filemode='w') 
# define a Handler which writes INFO messages or higher to the sys.stderr 
console = logging.StreamHandler() 
console.setLevel(logging.INFO) 
# set a format which is simpler for console use 
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') 
# tell the handler to use this format 
console.setFormatter(formatter) 
# add the handler to the root logger 
logging.getLogger('').addHandler(console) 

# Now, we can log to the root logger, or any other logger. First the root... 
logging.info('Jackdaws love my big sphinx of quartz.') 

# Now, define a couple of other loggers which might represent areas in your 
# application: 

logger1 = logging.getLogger('myapp.area1') 
logger2 = logging.getLogger('myapp.area2') 

logger1.debug('Quick zephyrs blow, vexing daft Jim.') 
logger1.info('How quickly daft jumping zebras vex.') 
logger2.warning('Jail zesty vixen who grabbed pay from quack.') 
logger2.error('The five boxing wizards jump quickly.') 

When you run this, on the console you will see

root  : INFO  Jackdaws love my big sphinx of quartz. 
myapp.area1 : INFO  How quickly daft jumping zebras vex. 
myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. 
myapp.area2 : ERROR The five boxing wizards jump quickly. 

and in the file you will see something like

10-22 22:19 root   INFO  Jackdaws love my big sphinx of quartz. 
10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. 
10-22 22:19 myapp.area1 INFO  How quickly daft jumping zebras vex. 
10-22 22:19 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. 
10-22 22:19 myapp.area2 ERROR The five boxing wizards jump quickly. 

As you can see, the DEBUG message only shows up in the file. The other messages are sent to both destinations.

This example uses console and file handlers, but you can use any number and combination of handlers you choose.

+3

+1在所有SO问题中最好的答案登录屏幕和文件 – 2013-12-02 09:11:49

+0

我喜欢这个答案,但我不确定这是什么原始的海报要求。 – 2015-02-20 03:09:32

+0

当复制上面那样的代码,后 'logging.info( '寒鸦爱我的石英大狮身人面像。')' 我得到以下错误: ... 文件“C:\ Anaconda2 \ LIB \记录\ __ init__.py“行467格式为 record.asctime = self.formatTime(record,self.datefmt) 格式化时间文件”C:\ Anaconda2 \ lib \ logging \ __ init__.py“,行425 s = time.strftime(datefmt,ct) ValueError:无效的格式字符串 任何人都可以帮忙吗? – riccio777 2017-10-08 09:52:17

1

卸下做这行你直接说你不不想完成:close()的第一行,它关闭stdout。

0

That is to say, when it closes, I think sys.stdout closes, so printing at all, and using this class again fails. I tried reimporting sys, and other dumb stuff, but I can't get it to work.

要回答你的问题,你不应该关门标准输出。 python解释器在启动时打开stdout,stdin和stderror。为了使打印工作,解释器需要stdout被打开。一旦模块被加载,重新导入sys不会执行任何操作。您需要重新加载模块。在这种特殊情况下,我不确定重装会解决问题,因为sys.stdout允许将stdout用作文件对象。

此外,我认为你的代码有一个错误,可能导致打印到 中断。在第2行中,您正在将一个MyWriter对象分配给sys.stdout。这可以通过在垃圾收集器删除未使用的stdout文件对象时关闭stdout来实现。

writer = MyWriter(sys.stdout, 'log.txt') 
sys.stdout = writer 
4

易peasy与Python 3.3及以上

与Python 3.3开始,这样做已成为显著容易,因为现在logging.basicConfig接受handlers =说法。

import logging 

level = logging.INFO 
format = ' %(message)s' 
handlers = [logging.FileHandler('filename.log'), logging.StreamHandler()] 
logging.basicConfig(level = level, format = format, handlers = handlers) 

logging.info('Hey, this is working!') 

但请注意,某些Python模块也可能会将日志消息发布到INFO级别。

这是它在哪里得心应手create a custom logging level,称为例如OK,5级的默认INFO水平以上和以下的默认WARNING 5级水平。