Souvent, j'ai besoin de sortir des données dans un fichier ou, si le fichier n'est pas spécifié, dans stdout. J'utilise l'extrait suivant:
if target:
with open(target, 'w') as h:
h.write(content)
else:
sys.stdout.write(content)
Je voudrais le réécrire et gérer les deux cibles de manière uniforme.
Dans le cas idéal, ce serait:
with open(target, 'w') as h:
h.write(content)
mais cela ne fonctionnera pas bien car sys.stdout est fermé en quittant le with
bloc et je ne le veux pas. Je ne veux pas non plus
stdout = open(target, 'w')
...
parce que j'aurais besoin de me rappeler de restaurer la sortie standard d'origine.
En relation:
- Rediriger stdout vers un fichier en Python?
- Handling Exceptions - article intéressant sur la gestion des exceptions en Python, par rapport à C ++
Éditer
Je sais que je peux envelopper target
, définir une fonction distincte ou utiliser le gestionnaire de contexte . Je recherche une solution de montage simple, élégante et idiomatique qui ne nécessiterait pas plus de 5 lignes
Réponses:
En sortant des sentiers battus ici, que diriez-vous d'une
open()
méthode personnalisée ?Utilisez-le comme ceci:
la source
Restez fidèle à votre code actuel. C'est simple et vous pouvez dire exactement ce qu'il fait simplement en le regardant.
Une autre façon serait avec un inline
if
:Mais ce n'est pas beaucoup plus court que ce que vous avez et cela semble sans doute pire.
Vous pouvez également rendre
sys.stdout
inaccessible, mais cela ne semble pas trop pythonique:la source
with unclosable(sys.stdout): ...
en le définissantsys.stdout.close = lambda: None
dans ce gestionnaire de contexte et en le réinitialisant à l'ancienne valeur par la suite. Mais cela semble un peu trop tiré par les cheveux ...sys.stdout
invisible, juste en notant que cela pouvait être fait. Il vaut mieux montrer de mauvaises idées et expliquer pourquoi elles sont mauvaises que de ne pas les mentionner et d'espérer qu'elles ne seront pas tombées par hasard par d'autres.Pourquoi LBYL quand vous pouvez EAFP?
Pourquoi le réécrire pour utiliser le bloc
with
/as
uniformément lorsque vous devez le faire fonctionner de manière alambiquée? Vous allez ajouter plus de lignes et réduire les performances.la source
for
boucle de Python se termine en interceptant une erreur StopIteration lancée par l'itérateur sur lequel elle boucle, je dirais que l'utilisation d'exceptions pour le contrôle de flux est tout à fait pythonique.target
c'est à ceNone
moment-là que sys.stdout est prévu, vous devez attraperTypeError
plutôt queIOError
.Autre solution possible: n'essayez pas d'éviter la méthode de sortie du gestionnaire de contexte, dupliquez simplement stdout.
la source
Une amélioration de la réponse de Wolph
Cela permet les E / S binaires et de passer d'éventuels arguments superflus à
open
iffilename
est en effet un nom de fichier.la source
J'opterais également pour une fonction wrapper simple, qui peut être assez simple si vous pouvez ignorer le mode (et par conséquent stdin vs stdout), par exemple:
la source
ValueError: I/O operation on closed file
si j'essaye d'écrire dans le fichier en dehors duwith open_or_stdout(..)
bloc. Qu'est-ce que je rate? sys.stdout n'est pas censé être fermé.D'accord, si nous nous engageons dans des guerres à une ligne, voici:
J'aime l'exemple original de Jacob tant que le contexte n'est écrit qu'à un seul endroit. Ce serait un problème si vous finissez par rouvrir le fichier pour de nombreuses écritures. Je pense que je prendrais simplement la décision une fois en haut du script et laisserais le système fermer le fichier à la sortie:
Vous pouvez inclure votre propre gestionnaire de sortie si vous pensez que c'est plus ordonné
la source
__del__
feraient cela.Si vous devez vraiment insister sur quelque chose de plus "élégant", c'est-à-dire un one-liner:
foo.txt
apparaît et contient le textefoo
.la source
Que diriez-vous d'ouvrir un nouveau fd pour sys.stdout? De cette façon, vous n'aurez aucun problème à le fermer:
la source
./script.py >> file
écraser le fichier au lieu de lui ajouter.Légère amélioration dans certains cas.
la source
Juste deux lignes supplémentaires si vous utilisez Python 3.3 ou supérieur: une ligne pour le supplément
import
et une ligne pour lestack.enter_context
.la source
Si c'est bien qui
sys.stdout
est fermé après lewith
corps, vous pouvez également utiliser des modèles comme celui-ci:ou encore plus généralement:
la source