A menudo necesito enviar datos a un archivo o, si el archivo no está especificado, a la salida estándar. Utilizo el siguiente fragmento:
if target:
with open(target, 'w') as h:
h.write(content)
else:
sys.stdout.write(content)
Me gustaría reescribirlo y manejar ambos objetivos de manera uniforme.
En el caso ideal sería:
with open(target, 'w') as h:
h.write(content)
pero esto no funcionará bien porque sys.stdout se cierra al salir del withbloque y no quiero eso. Yo tampoco quiero
stdout = open(target, 'w')
...
porque necesitaría recordar restaurar la salida estándar original.
Relacionado:
- ¿Redirigir stdout a un archivo en Python?
- Manejo de excepciones : artículo interesante sobre el manejo de excepciones en Python, en comparación con C ++
Editar
Sé que puedo ajustar target, definir una función separada o usar el administrador de contexto . Busco una solución sencilla, elegante e idiomática que no requiera más de 5 líneas.

Respuestas:
Solo pensando fuera de la caja aquí, ¿qué tal un
open()método personalizado ?Úselo así:
fuente
Cíñete a tu código actual. Es simple y puedes saber exactamente lo que está haciendo con solo mirarlo.
Otra forma sería con una línea
if:Pero eso no es mucho más corto de lo que tienes y posiblemente se ve peor.
También podría hacer
sys.stdoutque no se pueda cerrar, pero eso no parece demasiado Pythonic:fuente
with unclosable(sys.stdout): ...configurándolosys.stdout.close = lambda: Nonedentro de este administrador de contexto y restableciéndolo al valor anterior después. Pero esto parece un poco demasiado inverosímil ...sys.stdoutpueda cerrar, solo señalando que se podría hacer. Es mejor mostrar malas ideas y explicar por qué son malas que no mencionarlas y esperar que otros no las encuentren.¿Por qué LBYL cuando puede EAFP?
¿Por qué reescribirlo para usar el bloque
with/asuniformemente cuando tienes que hacerlo funcionar de una manera complicada? Agregará más líneas y reducirá el rendimiento.fuente
forbucle de Python sale al detectar un error de StopIteration arrojado por el iterador en el que está pasando, diría que usar excepciones para el control de flujo es completamente Pythonic.targetesNonecuando se pretende sys.stdout, necesita capturar enTypeErrorlugar deIOError.Otra posible solución: no intente evitar el método de salida del administrador de contexto, simplemente duplique stdout.
fuente
Una mejora de la respuesta de Wolph.
Esto permite IO binario y pasar eventuales argumentos extraños a
opensi defilenamehecho es un nombre de archivo.fuente
También optaría por una función contenedora simple, que puede ser bastante simple si puede ignorar el modo (y, en consecuencia, stdin vs stdout), por ejemplo:
fuente
ValueError: I/O operation on closed filesi intento escribir en el archivo fuera delwith open_or_stdout(..)bloque. ¿Qué me estoy perdiendo? sys.stdout no está destinado a cerrarse.De acuerdo, si nos estamos metiendo en guerras de una sola línea, aquí está:
Me gusta el ejemplo original de Jacob siempre y cuando el contexto esté escrito en un solo lugar. Sería un problema si vuelve a abrir el archivo para muchas escrituras. Creo que simplemente tomaría la decisión una vez en la parte superior del script y dejaría que el sistema cierre el archivo al salir:
Podría incluir su propio controlador de salida si cree que es más ordenado
fuente
__del__harían eso.Si realmente debes insistir en algo más "elegante", es decir, una frase:
foo.txtaparece y contiene el textofoo.fuente
¿Qué tal abrir un nuevo fd para sys.stdout? De esta forma no tendrás problemas para cerrarlo:
fuente
./script.py >> filesobrescriba el archivo en lugar de agregarlo.Ligera mejora en algunos casos.
fuente
Solo dos líneas adicionales si usa Python 3.3 o superior: una línea para el extra
importy una línea para elstack.enter_context.fuente
Si está bien que
sys.stdoutesté cerrado después delwithcuerpo, también puede usar patrones como este:o incluso más en general:
fuente