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 with
bloque 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.stdout
que no se pueda cerrar, pero eso no parece demasiado Pythonic:fuente
with unclosable(sys.stdout): ...
configurándolosys.stdout.close = lambda: None
dentro de este administrador de contexto y restableciéndolo al valor anterior después. Pero esto parece un poco demasiado inverosímil ...sys.stdout
pueda 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
/as
uniformemente cuando tienes que hacerlo funcionar de una manera complicada? Agregará más líneas y reducirá el rendimiento.fuente
for
bucle 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.target
esNone
cuando se pretende sys.stdout, necesita capturar enTypeError
lugar 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
open
si defilename
hecho 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 file
si 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.txt
aparece 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 >> file
sobrescriba 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
import
y una línea para elstack.enter_context
.fuente
Si está bien que
sys.stdout
esté cerrado después delwith
cuerpo, también puede usar patrones como este:o incluso más en general:
fuente