2012-02-17 17 views
19

Encontré algún código en línea que generalmente funciona, pero quiero usarlo varias veces en el mismo programa (escribir cosas diferentes en diferentes archivos, mientras sigo imprimiendo en la pantalla todo el tiempo).Imprimir en una pantalla y escribir en un archivo al mismo tiempo

Es decir, cuando se cierra, creo que sys.stdout se cierra, por lo que la impresión en absoluto, y el uso de esta clase otra vez falla. Traté de volver a importar el sistema y otras cosas tontas, pero no puedo hacer que funcione.

Aquí está el sitio, y el código 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

¿Cuándo se cierra? No veo nada que se cierre allí. –

+0

Debe aceptar la respuesta, realmente – gt6989b

Respuesta

83

Está intentando reproducir mal algo que la Biblioteca de Python Standard hace muy bien; por favor, consulte el logging module.

Con este módulo puede hacer exactamente lo que quiera, pero de una manera mucho más simple, estándar y extensible. Se puede proceder de la siguiente manera (en este ejemplo es un copiar/pegar desde el 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 La mejor respuesta en todas las preguntas de SO para iniciar sesión en la pantalla y el archivo –

+0

Me encanta esta respuesta, pero no estoy seguro de que esto es lo que el cartel original estaba pidiendo. –

+0

Al replicar exactamente el código anterior, después de 'logging.info ('Grajillas encanta mi gran esfinge de cuarzo.')' me sale el siguiente error: ... archivo "C: \ Anaconda2 \ lib \ tala \ __ init__.py ", línea 467, en formato record.asctime = self.formatTime (registro, self.datefmt) Archivo" C: \ Anaconda2 \ lib \ logging \ __ init__.py ", línea 425, en formato Hora s = time.strftime (datefmt, ct) ValueError: cadena de formato no válido ¿Alguien puede ayudar? – riccio777

1

eliminar la línea que está haciendo lo que se dice explícitamente Don 't want done: la primera línea de close(), que cierra 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.

Para responder a su pregunta , no deberías estar cerrando stdout. El intérprete de python abre stdout, stdin y stderror al inicio. Para que la impresión funcione, el intérprete requiere que stdout esté abierta. La reimportación de sys no hace nada una vez que se ha cargado un módulo. Necesitarías volver a cargar el módulo. En este caso particular, no estoy seguro de que una recarga pueda solucionar el problema, ya que sys.stdout permite que stdout se use como un objeto de archivo.

Además, creo que tiene un error en su código que puede estar causando la impresión de ruptura. En la línea 2 está asignando un objeto MyWriter a sys.stdout. Esto puede cerrando stdout cuando el recolector de basura elimina el objeto de archivo stdout no utilizado.

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

Fácil-peasy con Python 3.3 y por encima de

A partir de Python 3.3, al hacerlo, ha llegado a ser significativamente más fácil ya logging.basicConfig acepta ahora el argumento 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!') 

Obsérvese, sin embargo, que ciertos módulos de Python también pueden ser el envío de mensajes de registro a nivel INFO.

Aquí es donde es muy útil para create a custom logging level, llamado por ejemplo OK, 5 niveles por encima del nivel predeterminado INFO y 5 niveles por debajo del nivel predeterminado WARNING.

Cuestiones relacionadas