2012-02-17 22 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

いつ閉じますか?私はそこに終わる何も見ない。 –

+0

本当に答えを受け入れる必要があります。 – gt6989b

答えて

83

あなたは、Python標準ライブラリでうまくいくものをうまく再現しようとしていません。 logging moduleをご確認ください。

このモジュールを使用すると、必要なだけ正確に行うことができますが、はるかに簡単で標準的で拡張可能な方法で行うことができます。

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スクリーンとファイルにログオンするためのすべての質問にお答えします。 –

+0

私はこの回答が大好きですが、これは元のポスターが求めていたものです。 –

+0

上記正確にコードを複製する場合、 'logging.info( 'Jackdawsは、石英の私の大きなスフィンクスが大好きです。')' 後、私は次のエラーを取得: ... ファイル「C:\ Anaconda2 \ libに\ログをのフォーマットで\ __init__.py "の行467をフォーマットのファイル" C:\ Anaconda2 \ lib \ logging \ __init__.py "(425行目)のファイル: file.asctime = self.formatTime(record、self.datefmt) = time.strftime(datefmt、ct) ValueError:無効な書式文字列 誰でも手助けできますか? – riccio777

1

は、あなたが明示的にあなたのドンを言うことをやっている行を削除します't want done:stdoutを閉じるclose()の最初の行。

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.

は、あなたの質問に答えるために次のように続行することができます(この例ではlogging cookbookからのコピー/ペーストがあります) 、あなたは閉じるべきではありませんstdout。 Pythonインタプリタは起動時にstdout、stdin、およびstderrorを開きます。印刷が機能するためには、インタプリタは標準出力を開く必要があります。モジュールをロードした後は、Reimporting sysは何もしません。モジュールをリロードする必要があります。この特定のケースでは、sys.stdoutがstdoutをファイルオブジェクトとして使用できるので、リロードによって問題が解決されるかどうかはわかりません。

また、あなたのコードには、 の改行を引き起こしているかもしれないバグがあると思います。 2行目では、MyWriterオブジェクトをsys.stdoutに割り当てています。これは、ガベージコレクタが未使用のstdoutファイルオブジェクトを削除するときに、stdoutを閉じることによって可能になります。

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

のPython 3.3とPython 3.3以降で

上記で簡単peasy、そうすること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レベルにロギングメッセージを投稿することができることに注意してください。

それはたとえばOKを呼びかけ、create a custom logging levelに便利な出番は、デフォルトINFOレベル以上の5つのレベルとデフォルトWARNINGレベル以下の5つのレベル。

関連する問題