write example español python stdout

español - sys python example



¿Redirigir stdout a un archivo en Python? (10)

¿Cómo redirecciono stdout a un archivo arbitrario en Python?

Cuando se inicia un script de Python de larga duración (por ejemplo, una aplicación web) desde la sesión ssh y está en segundo plano, y la sesión ssh se cierra, la aplicación generará IOError y fallará en el momento en que intenta escribir en stdout. Necesitaba encontrar una manera de hacer que la aplicación y los módulos se envíen a un archivo en lugar de a la salida estándar para evitar fallas debido a IOError. Actualmente, empleo nohup para redirigir la salida a un archivo, y eso hace el trabajo, pero me preguntaba si había una manera de hacerlo sin usar nohup, por curiosidad.

Ya probé sys.stdout = open(''somefile'', ''w'') , pero esto no impide que algunos módulos externos sigan enviando a la terminal (o tal vez la línea sys.stdout = ... no se disparó en todos). Sé que debería funcionar con scripts más simples que he probado, pero aún no tengo tiempo para probar en una aplicación web todavía.


Aquí hay una variación de la respuesta de Yuda Prawira :

  • Implementar flush() y todos los atributos del archivo.
  • Escríbelo como un administrador de contexto
  • captura stderr también

.

import contextlib, sys @contextlib.contextmanager def log_print(file): # capture all outputs to a log file while still printing it class Logger: def __init__(self, file): self.terminal = sys.stdout self.log = file def write(self, message): self.terminal.write(message) self.log.write(message) def __getattr__(self, attr): return getattr(self.terminal, attr) logger = Logger(file) _stdout = sys.stdout _stderr = sys.stderr sys.stdout = logger sys.stderr = logger try: yield logger.log finally: sys.stdout = _stdout sys.stderr = _stderr with log_print(open(''mylogfile.log'', ''w'')): print(''hello world'') print(''hello world on stderr'', file=sys.stderr) # you can capture the output to a string with: # with log_print(io.StringIO()) as log: # .... # print(''[captured output]'', log.getvalue())


Basado en esta respuesta: https://.com/a/5916874/1060344 , aquí hay otra forma en la que descubrí cuál uso en uno de mis proyectos. Para lo que sea que reemplace sys.stderr o sys.stdout , debe asegurarse de que el reemplazo cumpla con file interfaz del file , especialmente si es algo que está haciendo porque stderr / stdout se usa en alguna otra biblioteca que no está bajo su control . Esa biblioteca puede estar usando otros métodos de archivo objeto.

Echa un vistazo de esta manera, donde todavía dejo que todo siga haciendo stderr / stdout (o cualquier otro archivo) y también envío el mensaje a un archivo de registro utilizando la función de registro de Python (pero realmente puedes hacer cualquier cosa con esto):

class FileToLogInterface(file): '''''' Interface to make sure that everytime anything is written to stderr, it is also forwarded to a file. '''''' def __init__(self, *args, **kwargs): if ''cfg'' not in kwargs: raise TypeError(''argument cfg is required.'') else: if not isinstance(kwargs[''cfg''], config.Config): raise TypeError( ''argument cfg should be a valid '' ''PostSegmentation configuration object i.e. '' ''postsegmentation.config.Config'') self._cfg = kwargs[''cfg''] kwargs.pop(''cfg'') self._logger = logging.getlogger(''access_log'') super(FileToLogInterface, self).__init__(*args, **kwargs) def write(self, msg): super(FileToLogInterface, self).write(msg) self._logger.info(msg)


Citado de PEP 343 - La declaración "con" (declaración de importación agregada):

Redirigir stdout temporalmente:

import sys from contextlib import contextmanager @contextmanager def stdout_redirected(new_stdout): save_stdout = sys.stdout sys.stdout = new_stdout try: yield None finally: sys.stdout = save_stdout

Utilizado de la siguiente manera:

with open(filename, "w") as f: with stdout_redirected(f): print "Hello world"

Esto no es seguro para subprocesos, por supuesto, pero ninguno de los dos está haciendo este mismo baile manualmente. En programas de un solo hilo (por ejemplo, en scripts) es una forma popular de hacer las cosas.


Hay contextlib.redirect_stdout() función contextlib.redirect_stdout() en Python 3.4:

from contextlib import redirect_stdout with open(''help.txt'', ''w'') as f: with redirect_stdout(f): print(''it now prints to `help.text`'')

Esto es similar a:

import sys from contextlib import contextmanager @contextmanager def redirect_stdout(new_target): old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout try: yield new_target # run some code with the replaced stdout finally: sys.stdout = old_target # restore to the previous value

que se puede utilizar en versiones anteriores de Python. La última versión no es reusable . Se puede hacer uno si se desea.

No redirige la salida estándar al nivel de descriptores de archivos, por ejemplo:

import os from contextlib import redirect_stdout stdout_fd = sys.stdout.fileno() with open(''output.txt'', ''w'') as f, redirect_stdout(f): print(''redirected to a file'') os.write(stdout_fd, b''not redirected'') os.system(''echo this also is not redirected'')

b''not redirected'' y ''echo this also is not redirected'' no son redirigidos al archivo output.txt .

Para redirigir al nivel del descriptor de archivo, se podría usar os.dup2() :

import os import sys from contextlib import contextmanager def fileno(file_or_fd): fd = getattr(file_or_fd, ''fileno'', lambda: file_or_fd)() if not isinstance(fd, int): raise ValueError("Expected a file (`.fileno()`) or a file descriptor") return fd @contextmanager def stdout_redirected(to=os.devnull, stdout=None): if stdout is None: stdout = sys.stdout stdout_fd = fileno(stdout) # copy stdout_fd before it is overwritten #NOTE: `copied` is inheritable on Windows when duplicating a standard stream with os.fdopen(os.dup(stdout_fd), ''wb'') as copied: stdout.flush() # flush library buffers that dup2 knows nothing about try: os.dup2(fileno(to), stdout_fd) # $ exec >&to except ValueError: # filename with open(to, ''wb'') as to_file: os.dup2(to_file.fileno(), stdout_fd) # $ exec > to try: yield stdout # allow code to be run with the redirected stdout finally: # restore stdout to its previous value #NOTE: dup2 makes stdout_fd inheritable unconditionally stdout.flush() os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied

El mismo ejemplo funciona ahora si se stdout_redirected() lugar de redirect_stdout() :

import os import sys stdout_fd = sys.stdout.fileno() with open(''output.txt'', ''w'') as f, stdout_redirected(f): print(''redirected to a file'') os.write(stdout_fd, b''it is redirected now/n'') os.system(''echo this is also redirected'') print(''this is goes back to stdout'')

La salida que previamente se imprimió en stdout ahora va a output.txt siempre que el stdout_redirected() contexto stdout_redirected() esté activo.

Nota: stdout.flush() no vacia los buffers de C stdio en Python 3 donde I / O se implementa directamente en las llamadas al sistema de read() / write() . Para vaciar todos los flujos de salida abiertos de C stdio, puede llamar a libc.fflush(None) explícitamente si alguna extensión de C usa E / S basada en stdio:

try: import ctypes from ctypes.util import find_library except ImportError: libc = None else: try: libc = ctypes.cdll.msvcrt # Windows except OSError: libc = ctypes.cdll.LoadLibrary(find_library(''c'')) def flush(stream): try: libc.fflush(None) stream.flush() except (AttributeError, ValueError, IOError): pass # unsupported

Podría usar el parámetro stdout para redirigir otras secuencias, no solo sys.stdout , por ejemplo, para fusionar sys.stderr y sys.stdout :

def merged_stderr_stdout(): # $ exec 2>&1 return stdout_redirected(to=sys.stdout, stdout=sys.stderr)

Ejemplo:

from __future__ import print_function import sys with merged_stderr_stdout(): print(''this is printed on stdout'') print(''this is also printed on stdout'', file=sys.stderr)

Nota: stdout_redirected() mezcla E / S en sys.stdout ( sys.stdout generalmente) y E / O sin búfer (operaciones en descriptores de archivo directamente). Cuidado, podría haber issues buffering .

Para responder, edite: podría usar python-daemon para demonizar su script y usar el módulo de logging (como sugirió @ erikb85 ) en lugar de declaraciones de print y simplemente redirigir stdout para su script de Python de larga ejecución que ejecuta ahora con nohup .


Las otras respuestas no cubrieron el caso en el que desea que los procesos bifurcados compartan su nueva salida estándar.

Para hacer eso:

from os import open, close, dup, O_WRONLY old = dup(1) close(1) open("file", O_WRONLY) # should open on 1 ..... do stuff and then restore close(1) dup(old) # should dup to 1 close(old) # get rid of left overs


Los programas escritos en otros idiomas (por ejemplo, C) tienen que hacer magia especial (llamada doble bifurcación) expresamente para desvincularse del terminal (y para evitar procesos zombie). Entonces, creo que la mejor solución es emularlos.

Una ventaja adicional de volver a ejecutar su programa es que puede elegir redirecciones en la línea de comandos, por ejemplo, /usr/bin/python mycoolscript.py 2>&1 1>/dev/null

Consulte esta publicación para obtener más información: ¿Cuál es la razón para realizar una bifurcación doble al crear un daemon?


Necesita un multiplexor de terminal como tmux o GNU screen

Me sorprende que un pequeño comentario de Ryan Amos a la pregunta original sea la única mención de una solución muy preferible a todas las otras que se ofrecen, sin importar qué tan inteligentes puedan ser los engaños de los pitones y la cantidad de upvotes que hayan recibido. Además del comentario de Ryan, tmux es una buena alternativa a la pantalla GNU.

Pero el principio es el mismo: si alguna vez desea dejar un trabajo en la terminal mientras se desconecta, vaya a la cafetería a tomar un sándwich, vaya al baño, vaya a su casa (etc.) y luego vuelva a conectarse a su Sesión de terminal desde cualquier lugar o cualquier computadora como si nunca hubiera estado fuera, los multiplexores de terminal son la respuesta. Piense en ellos como VNC o escritorio remoto para las sesiones de terminal. Cualquier otra cosa es una solución. Como beneficio adicional, cuando el jefe y / o el socio entran y, sin darse cuenta, presionas la ventana de tu terminal en lugar de la ventana del navegador con su contenido poco fiable, no habrás perdido las últimas 18 horas de procesamiento. !


Puedes probar esto mucho mejor

import sys class Logger(object): def __init__(self, filename="Default.log"): self.terminal = sys.stdout self.log = open(filename, "a") def write(self, message): self.terminal.write(message) self.log.write(message) sys.stdout = Logger("yourlogfilename.txt") print "Hello world !" # this is should be saved in yourlogfilename.txt


Si desea hacer la redirección dentro del script de Python, establecer sys.stdout en un objeto de archivo hace el truco:

import sys sys.stdout = open(''file'', ''w'') print ''test''

Un método mucho más común es usar la redirección de shell al ejecutar (lo mismo en Windows y Linux):

$ python foo.py > file


import sys sys.stdout = open(''stdout.txt'', ''w'')