Suite

L'enregistrement de chaque fichier dans la boucle for donne une ERREUR 000872 ?

L'enregistrement de chaque fichier dans la boucle for donne une ERREUR 000872 ?


Je suis débutant en programmation Python. Je sais, je pose une question vraiment idiote. J'essaie d'extraire le DEM pour chaque bassin versant d'un plus grand DEM. Par conséquent, j'utilise l'extrait par masque. Le plus grand DEM est au format raster tandis que les limites du bassin versant sont des polygones. J'ai le code python suivant qui fonctionne bien. Cependant, je ne parviens pas à enregistrer chaque DEM de bassin versant après extraction dans la boucle. en utilisant mon code, je ne peux enregistrer que le 1er bassin versant, puis il est écrit "ERREUR 000872 : Raster de sortie : sortie C:SubhasisProject-Biological_monitoringLIDAR-DEMi existe. Il ne peut pas être écrasé car l'écrasement est désactivé".

Code:

import arcpy, os from arcpy import env from arcpy.sa import * #set work environment env.workspace = "C:/Subhasis/Project-Biological_monitoring/Individual_watershed/Watershed_Final" outws="C:/Subhasis/Project-Biological_monitoring/LIDAR- DEM" # Consultez la licence d'extension ArcGIS Spatial Analyst arcpy.CheckOutExtension("Spatial") #List shapefile fcList = arcpy.ListFeatureClasses() for i in fcList: inRaster="nj10ftffil" outExtractByMask = ExtractByMask(inRaster, i) #outname= os.path.join(outws,i) #outExtractByMask.save(outname) outExtractByMask.save("C:/Subhasis/Project-Biological_monitoring/LIDAR-DEM/i")

Vous devez trouver un nom unique pour chaque sortie raster. Ce faisant, vous devez supprimer l'extension ".shp" du fichier de formes afin de l'utiliser dans le nom du raster en sortie. N'oubliez pas non plus que vous devez connaître les extensions raster d'entrée et de sortie dans votre script.

import arcpy, os from arcpy import env from arcpy.sa import * #set work environment env.workspace = "C:/Subhasis/Project-Biological_monitoring/Individual_watershed/Watershed_Final" # Assurez-vous de spécifier l'extension correcte pour le raster (par exemple " .tif") # Aucune extension = Format Esri Grid inRaster = 'C:/Subhasis/Project-Biological_monitoring/LIDAR-DEM/nj10ftffil' # Votre DEM outws="C:/Subhasis/Project-Biological_monitoring/LIDAR-DEM" # Check sortir la licence d'extension ArcGIS Spatial Analyst arcpy.CheckOutExtension("Spatial") #List shapefile fcList = arcpy.ListFeatureClasses() pour fc dans fcList : outExtractByMask = ExtractByMask(inRaster, fc) outname=os.path.join(outws,fc. strip(".")[0] + ".tif") # Supprimer l'extension ".shp" outExtractByMask.save(outname)

ma modification dans le code pour sortir correctement

pour fc dans fcList : out_euc = arcpy.sa.EucDistance(fc, 500000, 30) ext = os.path.splitext(fc) outname=os.path.join(output_path, ext[0] + ".tif") # Supprimer l'extension ".shp" out_euc.save(outname)

Script Bash pour supprimer le fichier le plus ancien d'un dossier

Comme l'a souligné Kos, il se peut qu'il ne soit pas possible de connaître le fichier le plus ancien (selon la date de création).

Si l'heure de modification vous convient et si le nom du fichier n'a pas de nouvelle ligne :

Il semble que vous puissiez supprimer le fichier modifié le plus ancien au lieu du fichier créé le plus ancien

Je considère que c'est la méthode la plus sûre, car elle ne casse pas sur les noms de fichiers contenant des nouvelles lignes :

  • stat --printf='%Y %n' * : imprime une liste séparée par NUL de l'heure de la dernière modification suivie du chemin du fichier pour chaque fichier dans le répertoire de travail actuel
  • sort -z : trie la liste en utilisant NUL comme séparateur de ligne
  • sed -zn '1s/[^ ] <1,>//p' : supprime la première occurrence d'une chaîne contenant un ou plusieurs caractères pas un espace suivi d'un espace de la première ligne terminée par NUL et l'imprime
  • xargs -0 rm : passe la ligne terminée par NUL à rm comme argument

Déterminer le fichier le plus ancien en fonction de « Access Time » ou « Modify Time » ?


Smtp.gmail.com de bash donne &ldquoError in certificate : l'émetteur du certificat pair n'est pas reconnu.&rdquo

J'avais besoin de mon script pour envoyer un e-mail à l'administrateur en cas de problème et l'entreprise n'utilise que Gmail. En suivant quelques instructions de publication, j'ai pu configurer mailx à l'aide d'un fichier .mailrc. il y a d'abord eu l'erreur de nss-config-dir que j'ai résolue en copiant des fichiers .db à partir d'un répertoire firefox. à ./certs et le viser dans mailrc. Un courrier a été envoyé.

Cependant, l'erreur ci-dessus s'est produite. Par miracle, il y avait un certificat Google dans le .db. Il est apparu avec cette commande :

Très probablement, il peut être ignoré, car le courrier a fonctionné de toute façon. Enfin, après avoir tiré quelques cheveux et de nombreuses lunettes, j'ai découvert comment me débarrasser de l'ennui.

Tout d'abord, exportez le certificat existant dans un fichier ASSCII :

Maintenant, réimportez ce fichier et marquez-le comme étant de confiance pour les certificats SSL, ala :

Après cela, la liste montre qu'il est digne de confiance :

Et mailx envoie sans accroc.

J'espère que cela sera utile à quelqu'un qui cherche à en finir avec l'erreur.

Aussi, je suis curieux de savoir quelque chose.

Comment pourrais-je obtenir ce certificat, s'il ne se trouvait pas par hasard dans la base de données mozilla ? Y a-t-il par exemple quelque chose comme ça ?


La boucle for se divise lorsqu'elle voit un espace comme un espace, une tabulation ou une nouvelle ligne. Donc, vous devez utiliser IFS (Internal Field Separator):

pour les boucles divisées sur n'importe quel espace (espace, tabulation, nouvelle ligne) par défaut le moyen le plus simple de travailler sur un ligne à la fois est d'utiliser une boucle de lecture while à la place, qui se divise en sauts de ligne :

J'aimerais attendre votre commande pour cracher un mot par ligne (c'est ce qui s'est passé lorsque je l'ai testé avec un fichier personnel). S'il se passe autre chose, je ne sais pas ce qui pourrait en être la cause.

Fonctionnement vérifié, pas la seule doublure que vous voulez probablement, mais il n'est pas possible de le faire avec élégance.

Voici une légère extension de la réponse de Mitchell Currie, que j'aime bien en raison de la faible portée des effets secondaires, ce qui évite d'avoir à définir une variable :

Je l'écrirais comme ceci :

car il nécessite le moins de modifications dans le script d'origine (sauf pour la solution utilisant IFS , mais il modifie le comportement de bash non seulement pour cette instruction de contrôle de boucle).

Mapfile est un moyen pratique de lire les lignes d'un fichier dans un tableau indexé, pas aussi portable que lu mais légèrement plus rapide. En utilisant la boucle for, vous évitez de créer un sous-shell.

Gardez à l'esprit que lorsque vous utilisez des pipelines, la boucle while sera placée dans un sous-shell. Les modifications à l'intérieur de la boucle while comme les variables ne se propageront pas à la partie externe du script.

(Meilleure solution) :

Dandalf s'est rapproché d'une solution fonctionnelle, mais il ne faut JAMAIS essayer d'attribuer le résultat de quantités inconnues d'entrées (c'est-à-dire trouver

/.gdfuse -name '*' ) aux variables ! Ou, au moins, essayez de faire une telle chose via une variable de tableau si vous insistez pour être si paresseux ! Alors, voici la solution de Dandalf faite sans la manœuvre dangereuse et en une seule ligne


Cela répertorie tous les fichiers (et uniquement les fichiers) dans le répertoire actuel :

De plus, si vous exécutez cette commande dans un fichier batch, vous devez doubler les signes %.

nxi). Ce fil peut aussi être très utile : stackoverflow.com/questions/112055/&hellip. &ndash Sk8erPeter 21 décembre 11 à 21:25

  • . fichiers dans le répertoire courant : pour %f dans (.*) faire @echo %f
  • . sous-répertoires dans le répertoire actuel : pour /D %s dans (.*) faire @echo %s
  • . fichiers en cours et tous les sous-répertoires : pour /R %f dans (.*) faire @echo %f
  • . sous-répertoires en cours et tous les sous-répertoires : pour /R /D %s dans (.*) faire @echo %s

Malheureusement, je n'ai trouvé aucun moyen d'itérer les fichiers et les sous-répertoires en même temps.

Utilisez simplement cygwin avec son bash pour beaucoup plus de fonctionnalités.

En dehors de cela : avez-vous remarqué que l'aide intégrée de MS Windows est une excellente ressource pour les descriptions de la syntaxe de la ligne de commande de cmd ?

Pour parcourir chaque fichier, une boucle for fonctionnera :

pour %%f dans (répertoirechemin*) faire ( quelque chose_ici )

Dans mon cas, je voulais aussi le contenu du fichier, le nom, etc.

Cela a conduit à quelques problèmes et j'ai pensé que mon cas d'utilisation pourrait aider. Voici une boucle qui lit les informations de chaque fichier '.txt' dans un répertoire et vous permet d'en faire quelque chose (setx par exemple).

*Limitation : val<=%%f n'obtiendra que la première ligne du fichier.

Il existe une différence subtile entre exécuter FOR à partir de la ligne de commande et à partir d'un fichier batch. Dans un fichier batch, vous devez mettre deux caractères % devant chaque référence de variable.

Cette boucle for listera tous les fichiers d'un répertoire.

J'ai eu du mal à faire fonctionner la réponse de jop avec un chemin absolu jusqu'à ce que je trouve cette référence : https://ss64.com/nt/for_r.html

L'exemple suivant parcourt tous les fichiers d'un répertoire donné par le chemin absolu.

Essayez "HELP FOR" dans cmd pour un guide complet

Ceci est le guide des commandes XP. http://www.ss64.com/nt/

À parcourir tous les fichiers et dossiers vous pouvez utiliser

À parcourir un dossier/répertoire nommé particulier et non des fichiers, puis utilisez /AD dans la même commande

Le code suivant crée un fichier Named "AllFilesInCurrentDirectorylist.txt" dans le répertoire courant, qui contient la liste de tous les fichiers (fichiers uniquement) dans le répertoire courant. Vérifiez-le

Il peut également utiliser la commande forfiles :

et aussi vérifier s'il s'agit d'un répertoire

Voici mon aller avec des commentaires dans le code.

Je suis juste en train de perfectionner mes compétences de biatch, alors pardonnez toutes les erreurs flagrantes.

J'ai essayé d'écrire une solution tout-en-un du mieux que je peux avec une petite modification là où l'utilisateur l'exige.

Quelques remarques importantes : Modifiez simplement la variable récursive sur FALSE si vous ne souhaitez que les fichiers et dossiers des répertoires racine traités. Sinon, il parcourt tous les dossiers et fichiers.

J'utiliserais vbscript (Windows Scripting Host), car en batch, je suis sûr que vous ne pouvez pas dire qu'un nom est un fichier ou un répertoire.

En vbs, ça peut être quelque chose comme ça :

J'utilise la commande xcopy avec l'option /L pour obtenir les noms de fichiers. Donc, si vous voulez obtenir un répertoire ou tous les fichiers du sous-répertoire, vous pouvez faire quelque chose comme ceci :

J'utilise simplement le c: comme destination car il existe toujours sur les systèmes Windows et il ne copie pas, donc cela n'a pas d'importance. si vous voulez aussi les sous-répertoires, utilisez simplement l'option /s à la fin. Vous pouvez également utiliser les autres commutateurs de xcopy si vous en avez besoin pour d'autres raisons.

Essayez ceci pour tester si un fichier est un répertoire :

Cela vous dira seulement si un fichier n'est PAS un répertoire, ce qui sera également vrai si le fichier n'existe pas, alors assurez-vous de vérifier cela d'abord si vous en avez besoin. Les carets (^) sont utilisés pour échapper aux symboles de redirection et la sortie de la liste de fichiers est redirigée vers NUL pour l'empêcher d'être affichée, tandis que la sortie d'erreur de la liste DIR est redirigée vers la sortie afin que vous puissiez tester par rapport au message de DIR "Fichier non trouvé ".

il compte les fichiers .msi et .exe dans votre répertoire (et dans le sous-répertoire). Cela fait donc également la différence entre les dossiers et les fichiers en tant qu'exécutables.

Ajoutez simplement une extension (.pptx .docx ..) si vous avez besoin de filtrer d'autres fichiers dans la boucle

Dans mon cas, j'ai dû supprimer tous les fichiers et dossiers sous un dossier temporaire. C'est donc ainsi que j'ai fini par procéder. J'ai dû exécuter deux boucles une pour le fichier et une pour les dossiers. Si les fichiers ou les dossiers ont des espaces dans leurs noms, vous devez utiliser " "


Pour désinfecter de manière récursive un projet, j'utilise ce oneliner :

git ls-files -z répertorie les fichiers dans le référentiel. Il prend un modèle facultatif comme paramètre supplémentaire qui peut être utile dans certains cas si vous souhaitez restreindre l'opération à certains fichiers/répertoires. Comme alternative, vous pouvez utiliser find -print0 . ou des programmes similaires pour répertorier les fichiers affectés - assurez-vous simplement qu'il émet des entrées délimitées par NUL.

tandis que IFS= read -rd '' f do . done parcourt les entrées, en gérant en toute sécurité les noms de fichiers qui incluent des espaces et/ou des sauts de ligne.

tail -c1 < "$f" lit le dernier caractère d'un fichier.

read -r _ sort avec un état de sortie différent de zéro si un saut de ligne de fin est manquant.

|| echo >> "$f" ajoute une nouvelle ligne au fichier si l'état de sortie de la commande précédente était différent de zéro.

Et alternativement pour OS X sed :

Cela ajoute à la fin du fichier seulement s'il ne se termine pas déjà par une nouvelle ligne. Donc, si vous l'exécutez deux fois, il n'ajoutera pas de nouvelle ligne :

donc echo "" >> noeol-file devrait faire l'affaire. (Ou vouliez-vous demander l'identification de ces fichiers et les réparer ?)

Éditer supprimé le "" de echo "" >> foo (voir le commentaire de @yuyichao) modifier2 ajouté à nouveau le "" (mais voir le commentaire de @Keith Thompson)

Une autre solution utilisant ed . Cette solution n'affecte que la dernière ligne et uniquement si est manquant :

Cela fonctionne essentiellement en ouvrant le fichier pour l'éditer via un script, le script est la seule commande w, qui réécrit le fichier sur le disque. Il est basé sur cette phrase trouvée dans la page de manuel ed(1) :

Un moyen simple, portable et compatible POSIX d'ajouter une nouvelle ligne finale absente à un fichier texte :

Cette approche n'a pas besoin de lire l'intégralité du fichier, elle peut simplement rechercher EOF et travailler à partir de là.

Cette approche n'a pas non plus besoin de créer des fichiers temporaires derrière votre dos (par exemple, sed -i), donc les liens physiques ne sont pas affectés.

echo ajoute une nouvelle ligne au fichier uniquement lorsque le résultat de la substitution de commande est une chaîne non vide. Notez que cela ne peut se produire que si le fichier n'est pas vide et que le dernier octet n'est pas un saut de ligne.

Si le dernier octet du fichier est un saut de ligne, tail le renvoie, puis la substitution de commande le supprime, le résultat est une chaîne vide. Le test -n échoue et echo ne s'exécute pas.

Si le fichier est vide, le résultat de la substitution de commande est également une chaîne vide, et encore une fois echo ne s'exécute pas. Ceci est souhaitable, car un fichier vide n'est pas un fichier texte invalide, ni l'équivalent d'un fichier texte non vide avec une ligne vide.

Voici un moyen de vérifier si une nouvelle ligne existe à la fin avant d'en ajouter une, en utilisant Python :

Est vraiment rapide.
Sur un fichier de taille moyenne seq 99999999 >file, cela prend des millisecondes.
Les autres solutions prennent du temps :

Fonctionne en ash, bash, lksh, mksh, ksh93, attsh et zsh mais pas en yash.

Si vous avez besoin d'une solution portable pour yash (et tous les autres shells répertoriés ci-dessus), cela peut devenir un peu plus complexe :

Le moyen le plus rapide de tester si le dernier octet d'un fichier est un saut de ligne est de lire uniquement ce dernier octet. Cela pourrait être fait avec tail -c1 file . Cependant, la manière simpliste de tester si la valeur de l'octet est une nouvelle ligne, en fonction de la suppression habituelle du shell d'une nouvelle ligne de fin à l'intérieur d'une extension de commande échoue (par exemple) dans yash, lorsque le dernier caractère du fichier est un UTF- 8 valeur.

Le moyen correct et conforme à POSIX de tous les shells (raisonnables) pour déterminer si le dernier octet d'un fichier est une nouvelle ligne consiste à utiliser xxd ou hexdump :

Ensuite, comparer la sortie de ci-dessus à 0A fournira un test robuste.
Il est utile d'éviter d'ajouter une nouvelle ligne à un fichier autrement vide.
Fichier qui ne parviendra pas à fournir un dernier caractère de 0A , bien sûr :

Court et doux. Cela prend très peu de temps car il ne fait que lire le dernier octet (recherche vers EOF). Peu importe si le fichier est gros. Ensuite, n'ajoutez qu'un octet si nécessaire.

Aucun fichier temporaire nécessaire ni utilisé. Aucun lien physique n'est affecté.

Si ce test est exécuté deux fois, il ne pas ajouter une autre nouvelle ligne.

Si vous souhaitez simplement ajouter rapidement une nouvelle ligne lors du traitement d'un pipeline, utilisez ceci :

Ensuite, bien sûr, vous pouvez le rediriger vers un fichier.

À condition qu'il n'y ait pas de valeurs nulles en entrée :

. suffirait de toujours ajouter un saut de ligne à la fin d'un fichier interne s'il n'en avait pas déjà un. Et il suffit de lire le fichier d'entrée une seule fois pour bien faire les choses.

Au moins dans les versions GNU, simplement grep '' ou awk 1 canonise son entrée, en ajoutant une nouvelle ligne finale si elle n'est pas déjà présente. Ils copient le fichier dans le processus, ce qui prend du temps s'il est volumineux (mais la source ne devrait pas être trop volumineuse pour être lu de toute façon ?) et met à jour le modtime à moins que vous ne fassiez quelque chose comme

(bien que cela puisse être correct sur un fichier que vous archivez parce que vous l'avez modifié) et il perd les liens physiques, les autorisations par défaut et les listes de contrôle d'accès, etc., à moins que vous ne soyez encore plus prudent.

Bien qu'il ne réponde pas directement à la question, voici un script connexe que j'ai écrit pour détecter les fichiers qui ne se terminent pas par une nouvelle ligne. C'est très rapide.

Le script perl lit une liste de noms de fichiers (éventuellement triés) à partir de stdin et pour chaque fichier, il lit le dernier octet pour déterminer si le fichier se termine par une nouvelle ligne ou non. Il est très rapide car il évite de lire tout le contenu de chaque fichier. Il affiche une ligne pour chaque fichier qu'il lit, préfixée par "error : » si une sorte d'erreur se produit, « vide : » si le fichier est vide (ne se termine pas par une nouvelle ligne !), « EOL : » (« fin de line") si le fichier se termine par une nouvelle ligne et "no EOL:" si le fichier ne se termine pas par une nouvelle ligne.

Remarque : le script ne gère pas les noms de fichiers contenant des sauts de ligne. Si vous êtes sur un système GNU ou BSD, vous pouvez gérer tous les noms de fichiers possibles en ajoutant -print0 pour rechercher, -z pour trier et -0 pour perl, comme ceci :

Bien sûr, vous devrez toujours trouver un moyen d'encoder les noms de fichiers avec des nouvelles lignes dans la sortie (à gauche comme exercice pour le lecteur).

La sortie peut être filtrée, si vous le souhaitez, pour ajouter une nouvelle ligne aux fichiers qui n'en ont pas, le plus simplement avec

L'absence d'une nouvelle ligne finale peut provoquer des bogues dans les scripts car certaines versions du shell et d'autres utilitaires ne géreront pas correctement une nouvelle ligne finale manquante lors de la lecture d'un tel fichier.

D'après mon expérience, l'absence d'une nouvelle ligne finale est due à l'utilisation de divers utilitaires Windows pour éditer des fichiers. Je n'ai jamais vu vim provoquer une nouvelle ligne finale manquante lors de l'édition d'un fichier, bien qu'il fasse rapport sur de tels fichiers.

Enfin, il existe des scripts beaucoup plus courts (mais plus lents) qui peuvent parcourir leurs entrées de nom de fichier pour imprimer les fichiers qui ne se terminent pas par une nouvelle ligne, tels que :


Ce n'est pas un problème de définir une variable dans une boucle. En fait, c'est une bonne pratique, puisque les identifiants doivent être limités à la plus petite portée possible.

Ce qui est mauvais, c'est de attribuer une variable dans une boucle si vous pouviez aussi bien l'affecter une fois avant la boucle s'exécute. Selon la complexité du côté droit de l'affectation, cela pourrait devenir assez coûteux et même dominer le temps d'exécution de la boucle. Si vous écrivez une boucle qui utilise la même valeur calculée dans toutes les itérations, vous devez absolument la calculer au dessus la boucle - c'est plus important que de minimiser sa portée.


Comment gérer plusieurs animations dans un seul fichier .blend ?

La façon dont j'utilise actuellement les animations n'est qu'une longue chronologie. Toutes mes animations séparées sont alignées dos à dos sur cette seule timeline. Je garde les numéros de trame de début/fin dans un fichier séparé.

Cela devient un problème lorsque je veux étendre, réduire ou modifier une animation. Étant donné que la durée de l'animation change, les images de début/fin de toutes les animations suivantes changent également. Cela m'oblige à analyser manuellement la chronologie et à mettre à jour mon fichier avec les nouvelles images de début/fin. Le fichier ressemble à ceci :

Où le format est le suivant :

J'aimerais ne plus faire ça. Comme cela peut devenir salissant.

Comment puis-je avoir plusieurs animations, chacune avec sa propre chronologie, dans un seul fichier .blend ?

Sinon, existe-t-il un moyen de placer des marqueurs dans ma chronologie qui peuvent être utilisés pour générer automatiquement un fichier comme ci-dessus. Les marqueurs se déplaceraient idéalement avec le cadre auquel ils sont attachés, et non avec le numéro de cadre spécifique.


13 TRAVAILLER AVEC DES FEUILLES DE CALCUL EXCEL

Bien que nous ne considérions pas souvent les feuilles de calcul comme des outils de programmation, presque tout le monde les utilise pour organiser les informations en structures de données bidimensionnelles, effectuer des calculs avec des formules et produire des résultats sous forme de graphiques. Dans les deux prochains chapitres, nous intégrerons Python dans deux applications de tableur populaires : Microsoft Excel et Google Sheets.

Excel est un tableur populaire et puissant pour Windows. Le module openpyxl permet à vos programmes Python de lire et de modifier des fichiers de feuille de calcul Excel. Par exemple, vous pourriez avoir la tâche ennuyeuse de copier certaines données d'une feuille de calcul et de les coller dans une autre. Ou vous devrez peut-être parcourir des milliers de lignes et n'en sélectionner qu'une poignée pour effectuer de petites modifications en fonction de certains critères. Ou vous devrez peut-être parcourir des centaines de feuilles de calcul des budgets des services, à la recherche de celles qui sont dans le rouge. Ce sont exactement le genre de tâches de tableur ennuyeuses et insensées que Python peut faire pour vous.

Bien qu'Excel soit un logiciel propriétaire de Microsoft, il existe des alternatives gratuites qui fonctionnent sous Windows, macOS et Linux. LibreOffice Calc et OpenOffice Calc fonctionnent tous deux avec Excel .xlsx format de fichier pour les feuilles de calcul, ce qui signifie que le module openpyxl peut également fonctionner sur les feuilles de calcul de ces applications. Vous pouvez télécharger le logiciel sur https://www.libreoffice.org/ et https://www.openoffice.org/, respectivement. Même si Excel est déjà installé sur votre ordinateur, vous trouverez peut-être ces programmes plus faciles à utiliser. Cependant, les captures d'écran de ce chapitre proviennent toutes d'Excel 2010 sous Windows 10.

Documents Excel

Tout d'abord, passons en revue quelques définitions de base : un tableur Excel est appelé un classeur. Un seul classeur est enregistré dans un fichier avec le .xlsx extension. Chaque classeur peut contenir plusieurs des draps (aussi appelé des feuilles de calcul). La feuille que l'utilisateur consulte actuellement (ou la dernière fois qu'elle a été consultée avant de fermer Excel) est appelée la feuille feuille active.

Chaque feuille a Colonnes (adressé par lettres commençant à UNE) et Lignes (adressées par des numéros commençant à 1). Une boîte à une colonne et une ligne particulières est appelée un cellule. Chaque cellule peut contenir un nombre ou une valeur textuelle. La grille de cellules avec des données constitue une feuille.

Installation du module openpyxl

Python n'est pas fourni avec OpenPyXL, vous devrez donc l'installer. Suivez les instructions d'installation des modules tiers dans l'annexe A le nom du module est openpyxl .

Ce livre utilise la version 2.6.2 d'OpenPyXL. Il est important que vous installiez cette version en exécutant pip install --user -U openpyxl==2.6.2 car les versions plus récentes d'OpenPyXL sont incompatibles avec les informations de ce livre. Pour tester s'il est correctement installé, saisissez ce qui suit dans le shell interactif :

Si le module a été correctement installé, cela ne devrait produire aucun message d'erreur. N'oubliez pas d'importer le module openpyxl avant d'exécuter les exemples de shell interactifs de ce chapitre, ou vous obtiendrez une erreur NameError : name 'openpyxl' is notdefined error.

Vous pouvez trouver la documentation complète pour OpenPyXL sur https://openpyxl.readthedocs.org/.

Lecture de documents Excel

Les exemples de ce chapitre utiliseront une feuille de calcul nommée exemple.xlsx stocké dans le dossier racine. Vous pouvez soit créer la feuille de calcul vous-même, soit la télécharger à partir de https://nostarch.com/automatestuff2/. La figure 13-1 montre les onglets des trois feuilles par défaut nommées Feuille1, Feuille2, et Feuille3 qu'Excel fournit automatiquement pour les nouveaux classeurs. (Le nombre de feuilles par défaut créées peut varier entre les systèmes d'exploitation et les tableurs.)

Figure 13-1 : Les onglets des feuilles d'un classeur se trouvent dans le coin inférieur gauche d'Excel.

La feuille 1 du fichier d'exemple doit ressembler au tableau 13-1. (Si vous n'avez pas téléchargé exemple.xlsx à partir du site Web, vous devez saisir vous-même ces données dans la feuille.)

Tableau 13-1 : Le exemple.xlsx Tableur

Maintenant que nous avons notre exemple de feuille de calcul, voyons comment nous pouvons le manipuler avec le module openpyxl.

Ouvrir des documents Excel avec OpenPyXL

Une fois que vous aurez importé le module openpyxl, vous pourrez utiliser la fonction openpyxl.load_workbook(). Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> type(wb)
<class 'openpyxl.workbook.workbook.Workbook'>

La fonction openpyxl.load_workbook() prend le nom de fichier et renvoie une valeur du type de données du classeur. Cet objet Workbook représente le fichier Excel, un peu comme un objet File représente un fichier texte ouvert.

Rappelez-vous que exemple.xlsx doit se trouver dans le répertoire de travail actuel pour que vous puissiez l'utiliser. Vous pouvez découvrir quel est le répertoire de travail actuel en important os et en utilisant os.getcwd() , et vous pouvez changer le répertoire de travail actuel en utilisant os.chdir() .

Obtenir des feuilles à partir du classeur

Vous pouvez obtenir une liste de tous les noms de feuilles dans le classeur en accédant à l'attribut sheetnames. Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> wb.sheetnames # Les noms des feuilles du classeur.
['Feuille1', 'Feuille2', 'Feuille3']
>>> sheet = wb['Sheet3'] # Récupère une feuille du classeur.
>>> feuille
<Feuille de travail "Feuille3">
>>> type(feuille)
<class 'openpyxl.worksheet.worksheet.Worksheet'>
>>> sheet.title # Récupère le titre de la feuille sous forme de chaîne.
'Feuille3'
>>> anotherSheet = wb.active # Récupère la feuille active.
>>> autreFeuille
<Feuille de travail "Feuille1">

Chaque feuille est représentée par un objet Worksheet, que vous pouvez obtenir en utilisant les crochets avec la chaîne de nom de feuille comme une clé de dictionnaire. Enfin, vous pouvez utiliser l'attribut actif d'un objet Workbook pour obtenir la feuille active du classeur. La feuille active est la feuille qui est en haut lorsque le classeur est ouvert dans Excel. Une fois que vous avez l'objet Worksheet, vous pouvez obtenir son nom à partir de l'attribut title.

Obtenir des cellules à partir des feuilles

Une fois que vous avez un objet Worksheet, vous pouvez accéder à un objet Cell par son nom. Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> sheet = wb['Sheet1'] # Récupère une feuille du classeur.
>>> sheet['A1'] # Récupère une cellule de la feuille.
<Cellule 'Feuille1'.A1>
>>> sheet['A1'].value # Récupère la valeur de la cellule.
dateheure.dateheure(2015, 4, 5, 13, 34, 2)
>>> c = feuille['B1'] # Récupère une autre cellule de la feuille.
>>> valeur c.
'Pommes'
>>> # Récupère la ligne, la colonne et la valeur de la cellule.
>>> 'Ligne %s, la colonne %s est %s' % (c.row, c.column, c.value)
« Ligne 1, la colonne B correspond aux pommes »
>>> 'La cellule %s est %s' % (c.coordinate, c.value)
« La cellule B1 est des pommes »
>>> feuille['C1'].valeur
73

L'objet Cell a un attribut value qui contient, sans surprise, la valeur stockée dans cette cellule. Les objets de cellule ont également des attributs de ligne , de colonne et de coordonnées qui fournissent des informations d'emplacement pour la cellule.

Ici, l'accès à l'attribut value de notre objet Cell pour la cellule B1 nous donne la chaîne 'Apples' . L'attribut de ligne nous donne l'entier 1 , l'attribut de colonne nous donne 'B' et l'attribut de coordonnée nous donne 'B1' .

OpenPyXL interprétera automatiquement les dates de la colonne A et les renverra sous forme de valeurs datetime plutôt que de chaînes. Le type de données datetime est expliqué plus en détail au chapitre 17.

Spécifier une colonne par lettre peut être délicat à programmer, d'autant plus qu'après la colonne Z, les colonnes commencent par utiliser deux lettres : AA, AB, AC, etc. Comme alternative, vous pouvez également obtenir une cellule en utilisant la méthode cell() de la feuille et en passant des entiers pour ses arguments de mot-clé de ligne et de colonne. Le premier entier de ligne ou de colonne est 1 , pas 0 . Continuez l'exemple de shell interactif en entrant ce qui suit :

>>> feuille.cell(ligne=1, colonne=2)
<Cellule 'Feuille1'.B1>
>>> feuille.cell(ligne=1, colonne=2).valeur
'Pommes'
>>> for i in range(1, 8, 2) : # Parcourir une ligne sur deux :
. print(i, feuille.cellule(ligne=i, colonne=2).valeur)
.
1 Pommes
3 poires
5 pommes
7 fraises

Comme vous pouvez le voir, en utilisant la méthode cell() de la feuille et en la passant row=1 et column=2 vous obtenez un objet Cell pour la cellule B1 , tout comme la spécification de la feuille['B1'] l'a fait. Ensuite, en utilisant la méthode cell() et ses arguments mot-clé, vous pouvez écrire une boucle for pour imprimer les valeurs d'une série de cellules.

Supposons que vous souhaitiez descendre dans la colonne B et imprimer la valeur dans chaque cellule avec un numéro de ligne impair. En passant 2 pour le paramètre « step » de la fonction range(), vous pouvez obtenir des cellules toutes les deux lignes (dans ce cas, toutes les lignes impaires). La variable i de la boucle for est transmise pour l'argument du mot-clé de ligne à la méthode cell(), tandis que 2 est toujours transmis pour l'argument du mot-clé de colonne. Notez que l'entier 2 , et non la chaîne 'B' , est transmis.

Vous pouvez déterminer la taille de la feuille avec les attributs max_row et max_column de l'objet Worksheet. Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> feuille = wb['Sheet1']
>>> sheet.max_row # Récupère le numéro de ligne le plus élevé.
7
>>> sheet.max_column # Récupère le numéro de colonne le plus élevé.
3

Notez que l'attribut max_column est un entier plutôt que la lettre qui apparaît dans Excel.

Conversion entre les lettres des colonnes et les nombres

Pour convertir des lettres en chiffres, appelez la fonction openpyxl.utils.column_index_from_string(). Pour convertir des nombres en lettres, appelez la fonction openpyxl.utils.get_column_letter(). Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> de openpyxl.utils importer get_column_letter, column_index_from_string
>>> get_column_letter(1) # Traduit la colonne 1 en une lettre.
'UNE'
>>> get_column_letter(2 )
'B'
>>> get_column_letter(27)
'AA'
>>> get_column_letter(900)
'AHP'
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> feuille = wb['Sheet1']
>>> get_column_letter(sheet.max_column)
'C'
>>> column_index_from_string('A') # Récupère le numéro de A.
1
>>> column_index_from_string('AA')
27

Après avoir importé ces deux fonctions du module openpyxl.utils, vous pouvez appeler get_column_letter() et lui transmettre un entier tel que 27 pour déterminer le nom de la lettre de la 27e colonne. La fonction column_index_string() fait l'inverse : vous lui passez la lettre du nom d'une colonne, et elle vous indique le numéro de cette colonne. Vous n'avez pas besoin d'avoir un classeur chargé pour utiliser ces fonctions. Si vous le souhaitez, vous pouvez charger un classeur, obtenir un objet Worksheet et utiliser un attribut Worksheet comme max_column pour obtenir un entier. Ensuite, vous pouvez passer cet entier à get_column_letter() .

Obtenir des lignes et des colonnes à partir des feuilles

Vous pouvez découper des objets Worksheet pour obtenir tous les objets Cell dans une ligne, une colonne ou une zone rectangulaire de la feuille de calcul. Ensuite, vous pouvez parcourir toutes les cellules de la tranche. Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> feuille = wb['Sheet1']
>>> tuple(sheet['A1':'C3']) # Récupère toutes les cellules de A1 à C3.
((<Cellule 'Feuille1'.A1>, <Cellule 'Feuille1'.B1>, <Cellule 'Feuille1'.C1>), (<Cell
'Feuille1'.A2>, <Cellule 'Feuille1'.B2>, <Cellule 'Feuille1'.C2>), (<Cellule 'Feuille1'.A3>,
<Cellule 'Feuille1'.B3>, <Cellule 'Feuille1'.C3>))
➊ >>> pour rowOfCellObjects dans la feuille['A1':'C3'] :
. pour cellObj dans rowOfCellObjects :
. print(cellObj.coordinate, cellObj.value)
. print('--- FIN DE LIGNE ---')

A1 05-04-2015 13:34:02
B1 Pommes
C1 73
--- FIN DE LIGNE ---
A2 05-04-2015 03:41:23
B2 Cerises
C2 85
--- FIN DE LIGNE ---
A3 2015-04-06 12:46:51
Poires B3
C3 14
--- FIN DE LIGNE ---

Ici, nous spécifions que nous voulons les objets Cell dans la zone rectangulaire de A1 à C3, et nous obtenons un objet Generator contenant les objets Cell dans cette zone. Pour nous aider à visualiser cet objet Generator, nous pouvons utiliser tuple() dessus pour afficher ses objets Cell dans un tuple.

Ce tuple contient trois tuples : un pour chaque ligne, du haut de la zone souhaitée vers le bas. Chacun de ces trois tuples internes contient les objets Cell dans une rangée de notre zone souhaitée, de la cellule la plus à gauche à la droite. Donc, dans l'ensemble, notre tranche de la feuille contient tous les objets Cell dans la zone de A1 à C3, en commençant par la cellule en haut à gauche et en se terminant par la cellule en bas à droite.

Pour imprimer les valeurs de chaque cellule de la zone, nous utilisons deux boucles for. La boucle for externe passe sur chaque ligne de la tranche ➊ . Ensuite, pour chaque ligne, la boucle for imbriquée parcourt chaque cellule de cette ligne ➋ .

Pour accéder aux valeurs des cellules dans une ligne ou une colonne particulière, vous pouvez également utiliser l'attribut de lignes et de colonnes d'un objet Feuille de calcul. Ces attributs doivent être convertis en listes avec la fonction list() avant de pouvoir utiliser les crochets et un index avec eux. Saisissez ce qui suit dans le shell interactif :

>>> importer openpyxl
>>> wb = openpyxl.load_workbook('exemple.xlsx')
>>> feuille = wb.active
>>> list(sheet.columns)[1] # Récupère les cellules de la deuxième colonne.
(<Cell 'Feuille1'.B1>, <Cell 'Feuille1'.B2>, <Cell 'Feuille1'.B3>, <Cell 'Feuille1'.
B4>, <Cellule 'Feuille1'.B5>, <Cellule 'Feuille1'.B6>, <Cellule 'Feuille1'.B7>)
>>> pour cellObj dans list(sheet.columns)[1] :
print(cellObj.value)

Pommes
Cerises
Poires
Des oranges
Pommes
Bananes
Fraises

L'utilisation de l'attribut rows sur un objet Worksheet vous donnera un tuple de tuples. Chacun de ces tuples internes représente une ligne et contient les objets Cell de cette ligne. L'attribut colonnes vous donne également un tuple de tuples, chacun des tuples internes contenant les objets Cell dans une colonne particulière. Pour exemple.xlsx, since there are 7 rows and 3 columns, rows gives us a tuple of 7 tuples (each containing 3 Cell objects), and columns gives us a tuple of 3 tuples (each containing 7 Cell objects).

To access one particular tuple, you can refer to it by its index in the larger tuple. For example, to get the tuple that represents column B, you use list(sheet.columns)[1] . To get the tuple containing the Cell objects in column A, you’d use list(sheet.columns)[0] . Once you have a tuple representing one row or column, you can loop through its Cell objects and print their values.

Workbooks, Sheets, Cells

As a quick review, here’s a rundown of all the functions, methods, and data types involved in reading a cell out of a spreadsheet file:

  1. Import the openpyxl module.
  2. Call the openpyxl.load_workbook() function.
  3. Get a Workbook object.
  4. Use the active or sheetnames attributes.
  5. Get a Worksheet object.
  6. Use indexing or the cell() sheet method with row and column keyword arguments.
  7. Get a Cell object.
  8. Read the Cell object’s value attribute.

Project: Reading Data from a Spreadsheet

Say you have a spreadsheet of data from the 2010 US Census and you have the boring task of going through its thousands of rows to count both the total population and the number of census tracts for each county. (A census tract is simply a geographic area defined for the purposes of the census.) Each row represents a single census tract. We’ll name the spreadsheet file censuspopdata.xlsx, and you can download it from https://nostarch.com/automatestuff2/. Its contents look like Figure 13-2.

Figure 13-2: The censuspopdata.xlsx spreadsheet

Even though Excel can calculate the sum of multiple selected cells, you’d still have to select the cells for each of the 3,000-plus counties. Even if it takes just a few seconds to calculate a county’s population by hand, this would take hours to do for the whole spreadsheet.

In this project, you’ll write a script that can read from the census spreadsheet file and calculate statistics for each county in a matter of seconds.

This is what your program does:

  1. Reads the data from the Excel spreadsheet
  2. Counts the number of census tracts in each county
  3. Counts the total population of each county
  4. Prints the results

This means your code will need to do the following:

  1. Open and read the cells of an Excel document with the openpyxl module.
  2. Calculate all the tract and population data and store it in a data structure.
  3. Write the data structure to a text file with the .py extension using the pprint module.

Step 1: Read the Spreadsheet Data

There is just one sheet in the censuspopdata.xlsx spreadsheet, named 'Population by Census Tract' , and each row holds the data for a single census tract. The columns are the tract number (A), the state abbreviation (B), the county name (C), and the population of the tract (D).

Open a new file editor tab and enter the following code. Save the file as readCensusExcel.py.

#! python3
# readCensusExcel.py - Tabulates population and number of census tracts for
# each county.

➊ import openpyxl, pprint
print('Opening workbook. ')
➋ wb = openpyxl.load_workbook('censuspopdata.xlsx')
➌ sheet = wb['Population by Census Tract']
countyData = <>

# TODO: Fill in countyData with each county's population and tracts.
print('Reading rows. ')
➍ for row in range(2, sheet.max_row + 1):
# Each row in the spreadsheet has data for one census tract.
state = sheet['B' + str(row)].value
county = sheet['C' + str(row)].value
pop = sheet['D' + str(row)].value

# TODO: Open a new text file and write the contents of countyData to it.

This code imports the openpyxl module, as well as the pprint module that you’ll use to print the final county data ➊ . Then it opens the censuspopdata.xlsx file ➋ , gets the sheet with the census data ➌ , and begins iterating over its rows ➍ .

Note that you’ve also created a variable named countyData , which will contain the populations and number of tracts you calculate for each county. Before you can store anything in it, though, you should determine exactly how you’ll structure the data inside it.

Step 2: Populate the Data Structure

The data structure stored in countyData will be a dictionary with state abbreviations as its keys. Each state abbreviation will map to another dictionary, whose keys are strings of the county names in that state. Each county name will in turn map to a dictionary with just two keys, 'tracts' and 'pop' . These keys map to the number of census tracts and population for the county. For example, the dictionary will look similar to this:

If the previous dictionary were stored in countyData , the following expressions would evaluate like this:

More generally, the countyData dictionary’s keys will look like this:

countyData[ state abbrev ][ county ]['tracts']
countyData[ state abbrev ][ county ]['pop']

Now that you know how countyData will be structured, you can write the code that will fill it with the county data. Add the following code to the bottom of your program:

#! python 3
# readCensusExcel.py - Tabulates population and number of census tracts for
# each county.

for row in range(2, sheet.max_row + 1):
# Each row in the spreadsheet has data for one census tract.
state = sheet['B' + str(row)].value
county = sheet['C' + str(row)].value
pop = sheet['D' + str(row)].value

# Make sure the key for this state exists.
➊ countyData.setdefault(state, <>)
# Make sure the key for this county in this state exists.
➋ countyData[state].setdefault(county, <'tracts': 0, 'pop': 0>)

# Each row represents one census tract, so increment by one.
➌ countyData[state][county]['tracts'] += 1
# Increase the county pop by the pop in this census tract.
➍ countyData[state][county]['pop'] += int(pop)

# TODO: Open a new text file and write the contents of countyData to it.

The last two lines of code perform the actual calculation work, incrementing the value for tracts ➌ and increasing the value for pop ➍ for the current county on each iteration of the for loop.

The other code is there because you cannot add a county dictionary as the value for a state abbreviation key until the key itself exists in countyData . (That is, countyData['AK']['Anchorage']['tracts'] += 1 will cause an error if the ' AK' key doesn’t exist yet.) To make sure the state abbreviation key exists in your data structure, you need to call the setdefault() method to set a value if one does not already exist for state ➊ .

Just as the countyData dictionary needs a dictionary as the value for each state abbreviation key, each of ceux dictionaries will need its own dictionary as the value for each county key ➋ . And each of ceux dictionaries in turn will need keys 'tracts' and 'pop' that start with the integer value 0 . (If you ever lose track of the dictionary structure, look back at the example dictionary at the start of this section.)

Since setdefault() will do nothing if the key already exists, you can call it on every iteration of the for loop without a problem.

Step 3: Write the Results to a File

After the for loop has finished, the countyData dictionary will contain all of the population and tract information keyed by county and state. At this point, you could program more code to write this to a text file or another Excel spreadsheet. For now, let’s just use the pprint.pformat() function to write the countyData dictionary value as a massive string to a file named census2010.py. Add the following code to the bottom of your program (making sure to keep it unindented so that it stays outside the for loop):

#! python 3
# readCensusExcel.py - Tabulates population and number of census tracts for
# each county.

for row in range(2, sheet.max_row + 1):
-- coupe --

# Open a new text file and write the contents of countyData to it.
print('Writing results. ')
resultFile = open('census2010.py', 'w')
resultFile.write('allData = ' + pprint.pformat(countyData))
resultFile.close()
print('Done.')

The pprint.pformat() function produces a string that itself is formatted as valid Python code. By outputting it to a text file named census2010.py, you’ve generated a Python program from your Python program! This may seem complicated, but the advantage is that you can now import census2010.py just like any other Python module. In the interactive shell, change the current working directory to the folder with your newly created census2010.py file and then import it:

>>> import census2010
>>> census2010.allData['AK']['Anchorage']
<'pop': 291826, 'tracts': 55>
>>> anchoragePop = census2010.allData['AK']['Anchorage']['pop']
>>> print('The 2010 population of Anchorage was ' + str(anchoragePop))
The 2010 population of Anchorage was 291826

Le readCensusExcel.py program was throwaway code: once you have its results saved to census2010.py, you won’t need to run the program again. Whenever you need the county data, you can just run import census2010 .

Calculating this data by hand would have taken hours this program did it in a few seconds. Using OpenPyXL, you will have no trouble extracting information that is saved to an Excel spreadsheet and performing calculations on it. You can download the complete program from https://nostarch.com/automatestuff2/.

Ideas for Similar Programs

Many businesses and offices use Excel to store various types of data, and it’s not uncommon for spreadsheets to become large and unwieldy. Any program that parses an Excel spreadsheet has a similar structure: it loads the spreadsheet file, preps some variables or data structures, and then loops through each of the rows in the spreadsheet. Such a program could do the following:

  • Compare data across multiple rows in a spreadsheet.
  • Open multiple Excel files and compare data between spreadsheets.
  • Check whether a spreadsheet has blank rows or invalid data in any cells and alert the user if it does.
  • Read data from a spreadsheet and use it as the input for your Python programs.

Writing Excel Documents

OpenPyXL also provides ways of writing data, meaning that your programs can create and edit spreadsheet files. With Python, it’s simple to create spreadsheets with thousands of rows of data.

Creating and Saving Excel Documents

Call the openpyxl.Workbook() function to create a new, blank Workbook object. Saisissez ce qui suit dans le shell interactif :

>>> import openpyxl
>>> wb = openpyxl.Workbook() # Create a blank workbook.
>>> wb.sheetnames # It starts with one sheet.
['Sheet']
>>> sheet = wb.active
>>> sheet.title
'Sheet'
>>> sheet.title = 'Spam Bacon Eggs Sheet' # Change title.
>>> wb.sheetnames
['Spam Bacon Eggs Sheet']

The workbook will start off with a single sheet named Feuille. You can change the name of the sheet by storing a new string in its title attribute.

Any time you modify the Workbook object or its sheets and cells, the spreadsheet file will not be saved until you call the save() workbook method. Enter the following into the interactive shell (with exemple.xlsx in the current working directory):

>>> import openpyxl
>>> wb = openpyxl.load_workbook('example.xlsx')
>>> sheet = wb.active
>>> sheet.title = 'Spam Spam Spam'
>>> wb.save('example_copy.xlsx') # Save the workbook.

Here, we change the name of our sheet. To save our changes, we pass a filename as a string to the save() method. Passing a different filename than the original, such as 'example_copy.xlsx' , saves the changes to a copy of the spreadsheet.

Whenever you edit a spreadsheet you’ve loaded from a file, you should always save the new, edited spreadsheet to a different filename than the original. That way, you’ll still have the original spreadsheet file to work with in case a bug in your code caused the new, saved file to have incorrect or corrupt data.

Creating and Removing Sheets

Sheets can be added to and removed from a workbook with the create_sheet() method and del operator. Saisissez ce qui suit dans le shell interactif :

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> wb.sheetnames
['Sheet']
>>> wb.create_sheet() # Add a new sheet.
<Worksheet "Sheet1">
>>> wb.sheetnames
['Sheet', 'Sheet1']
>>> # Create a new sheet at index 0.
>>> wb.create_sheet(index=0, title='First Sheet')
<Worksheet "First Sheet">
>>> wb.sheetnames
['First Sheet', 'Sheet', 'Sheet1']
>>> wb.create_sheet(index=2, title='Middle Sheet')
<Worksheet "Middle Sheet">
>>> wb.sheetnames
['First Sheet', 'Sheet', 'Middle Sheet', 'Sheet1']

The create_sheet() method returns a new Worksheet object named Sheet X , which by default is set to be the last sheet in the workbook. Optionally, the index and name of the new sheet can be specified with the index and title keyword arguments.

Continue the previous example by entering the following:

>>> wb.sheetnames
['First Sheet', 'Sheet', 'Middle Sheet', 'Sheet1']
>>> del wb['Middle Sheet']
>>> del wb['Sheet1']
>>> wb.sheetnames
['First Sheet', 'Sheet']

You can use the del operator to delete a sheet from a workbook, just like you can use it to delete a key-value pair from a dictionary.

Remember to call the save() method to save the changes after adding sheets to or removing sheets from the workbook.

Writing Values to Cells

Writing values to cells is much like writing values to keys in a dictionary. Enter this into the interactive shell:

>>> import openpyxl
>>> wb = openpyxl.Workbook()
>>> sheet = wb['Sheet']
>>> sheet['A1'] = 'Hello, world!' # Edit the cell's value.
>>> sheet['A1'].value
'Hello, world!'

If you have the cell’s coordinate as a string, you can use it just like a dictionary key on the Worksheet object to specify which cell to write to.

Project: Updating a Spreadsheet

In this project, you’ll write a program to update cells in a spreadsheet of produce sales. Your program will look through the spreadsheet, find specific kinds of produce, and update their prices. Download this spreadsheet from https://nostarch.com/automatestuff2/. Figure 13-3 shows what the spreadsheet looks like.

Figure 13-3: A spreadsheet of produce sales

Each row represents an individual sale. The columns are the type of produce sold (A), the cost per pound of that produce (B), the number of pounds sold (C), and the total revenue from the sale (D). The TOTAL column is set to the Excel formula =ROUND(B3*C3, 2), which multiplies the cost per pound by the number of pounds sold and rounds the result to the nearest cent. With this formula, the cells in the TOTAL column will automatically update themselves if there is a change in column B or C.

Now imagine that the prices of garlic, celery, and lemons were entered incorrectly, leaving you with the boring task of going through thousands of rows in this spreadsheet to update the cost per pound for any garlic, celery, and lemon rows. You can’t do a simple find-and-replace for the price, because there might be other items with the same price that you don’t want to mistakenly “correct.” For thousands of rows, this would take hours to do by hand. But you can write a program that can accomplish this in seconds.

Your program does the following:

This means your code will need to do the following:

  1. Open the spreadsheet file.
  2. For each row, check whether the value in column A is Celery , Garlic , or Lemon .
  3. If it is, update the price in column B.
  4. Save the spreadsheet to a new file (so that you don’t lose the old spreadsheet, just in case).

Step 1: Set Up a Data Structure with the Update Information

The prices that you need to update are as follows:

You could write code like this:

if produceName == 'Celery':
cellObj = 1.19
if produceName == 'Garlic':
cellObj = 3.07
if produceName == 'Lemon':
cellObj = 1.27

Having the produce and updated price data hardcoded like this is a bit inelegant. If you needed to update the spreadsheet again with different prices or different produce, you would have to change a lot of the code. Every time you change code, you risk introducing bugs.

A more flexible solution is to store the corrected price information in a dictionary and write your code to use this data structure. In a new file editor tab, enter the following code:

#! python3
# updateProduce.py - Corrects costs in produce sales spreadsheet.

wb = openpyxl.load_workbook('produceSales.xlsx')
sheet = wb['Sheet']

# The produce types and their updated prices
PRICE_UPDATES = <'Garlic': 3.07,
'Celery': 1.19,
'Lemon': 1.27>

# TODO: Loop through the rows and update the prices.

Save this as updateProduce.py. If you need to update the spreadsheet again, you’ll need to update only the PRICE_UPDATES dictionary, not any other code.

Step 2: Check All Rows and Update Incorrect Prices

The next part of the program will loop through all the rows in the spreadsheet. Add the following code to the bottom of updateProduce.py:

#! python3
# updateProduce.py - Corrects costs in produce sales spreadsheet.

# Loop through the rows and update the prices.
➊ for rowNum in range(2, sheet.max_row): # skip the first row
➋ produceName = sheet.cell(row=rowNum, column=1).value
➌ if produceName in PRICE_UPDATES:
sheet.cell(row=rowNum, column=2).value = PRICE_UPDATES[produceName]

We loop through the rows starting at row 2, since row 1 is just the header ➊ . The cell in column 1 (that is, column A) will be stored in the variable produceName ➋ . If produceName exists as a key in the PRICE_UPDATES dictionary ➌ , then you know this is a row that must have its price corrected. The correct price will be in PRICE_UPDATES[produceName] .

Notice how clean using PRICE_UPDATES makes the code. Only one if statement, rather than code like if produceName == 'Garlic': , is necessary for every type of produce to update. And since the code uses the PRICE_UPDATES dictionary instead of hardcoding the produce names and updated costs into the for loop, you modify only the PRICE_UPDATES dictionary and not the code if the produce sales spreadsheet needs additional changes.

After going through the entire spreadsheet and making changes, the code saves the Workbook object to updatedProduceSales.xlsx ➍ . It doesn’t overwrite the old spreadsheet just in case there’s a bug in your program and the updated spreadsheet is wrong. After checking that the updated spreadsheet looks right, you can delete the old spreadsheet.

You can download the complete source code for this program from https://nostarch.com/automatestuff2/.

Ideas for Similar Programs

Since many office workers use Excel spreadsheets all the time, a program that can automatically edit and write Excel files could be really useful. Such a program could do the following:

  • Read data from one spreadsheet and write it to parts of other spreadsheets.
  • Read data from websites, text files, or the clipboard and write it to a spreadsheet.
  • Automatically “clean up” data in spreadsheets. For example, it could use regular expressions to read multiple formats of phone numbers and edit them to a single, standard format.

Setting the Font Style of Cells

Styling certain cells, rows, or columns can help you emphasize important areas in your spreadsheet. In the produce spreadsheet, for example, your program could apply bold text to the potato, garlic, and parsnip rows. Or perhaps you want to italicize every row with a cost per pound greater than $5. Styling parts of a large spreadsheet by hand would be tedious, but your programs can do it instantly.

To customize font styles in cells, important, import the Font() function from the openpyxl.styles module.

from openpyxl.styles import Font

This allows you to type Font() instead of openpyxl.styles.Font() . (See “Importing Modules” on page 47 to review this style of import statement.)

Here’s an example that creates a new workbook and sets cell A1 to have a 24-point, italicized font. Saisissez ce qui suit dans le shell interactif :

>>> import openpyxl
>>> from openpyxl.styles import Font
>>> wb = openpyxl.Workbook()
>>> sheet = wb['Sheet']
➊ >>> italic24Font = Font(size=24, italic=True) # Create a font.
➋ >>> sheet['A1'].font = italic24Font # Apply the font to A1.
>>> sheet['A1'] = 'Hello, world!'
>>> wb.save('styles.xlsx')

In this example, Font(size=24, italic=True) returns a Font object, which is stored in italic24Font ➊ . The keyword arguments to Font() , size and italic , configure the Font object’s styling information. And when sheet['A1'].font is assigned the italic24Font object ➋ , all that font styling information gets applied to cell A1.

Font Objects

To set font attributes, you pass keyword arguments to Font() . Table 13-2 shows the possible keyword arguments for the Font() function.


Résolution

To resolve this issue, follow these steps. After you complete each step, test to determine whether the issue is resolved.

Note Windows Media Player supports the most common media file formats. However, it does not support every media file format that is currently available. In step 1, make sure that Windows Media Player supports the format of the file that you are trying to play. If Windows Media Player does not support that format, do not perform the steps after step 1. Instead, contact the distributor of that file to see whether a viewer for the file is available.

Note Because there are several versions of Microsoft Windows, the following steps may be different on your computer. If they are, see your product documentation to complete these steps.

Verify that Windows Media Player supports the file format that you are trying to play. Windows Media Player supports the following file formats:

Windows Media formats: .asf, .asx, .avi, .wav, .wax, .wma, .wm, .wmv

Moving Pictures Experts Group (MPEG) formats: .m3u, .mp2v, .mpg, .mpeg, .m1v, .mp2, .mp3, .mpa, .mpe, .mpv2

Musical Instrument Digital Interface (MIDI) formats: .mid, .midi, .rmi

Note Windows Media Player does not support playing .avi files that were created by using the Microsoft MPEG4v3 codec. Microsoft supports MPEG4v3 files in .asf streaming format only. These files are not supported in an .avi file type. To play the file, you must encode the file again by using the original source in a supported format, such as the .wmv format. To do this, you can use the Windows Media Encoder. For additional information, visit the following Microsoft Web site, and then click Windows Media Encoder dans le Select Download list:

http://www.microsoft.com/windows/windowsmedia/download If you have access to the original source, contact the creator of the file and request that the creator convert the file to a supported Windows Media Player file format.

Verify that you can play a media file that uses the same file name extension as the file that you were playing when you received the error message.

For descriptions and samples of file formats that are supported by Windows Media Player, click the following article number to view the article in the Microsoft Knowledge Base:

316992 Windows Media Player multimedia file formats
If the other file plays correctly, the original file you that were trying to play may be damaged. If you receive an error message when you play both of the files, go to the next step.

Remove Windows Media Player, restart the computer, and then reinstall Windows Media Player.

To remove Windows Media Player, follow these steps:

Cliquez sur Début, click Panneau de commande, puis cliquez sur Ajouter ou supprimer des programmes.

Dans le Currently installed programs list, click Microsoft Windows Media Player, puis cliquez sur Change/Remove.

When you are prompted to confirm the removal, click
Oui.

Note You cannot remove the built-in version of Windows Media Player by using this method. For additional information about how to remove Windows Media Player 9 Series, visit the following Microsoft Web site:

To download the latest version of Windows Media Player, visit the following Microsoft Web site:

Reinstall the latest version of Microsoft DirectX.
For additional information about troubleshooting and installing DirectX, click the following article numbers to view the articles in the Microsoft Knowledge Base:

179113 How to download and install DirectX

157730 How to determine the version of DirectX using the DirectX Diagnostic Tool

Verify that you are using the correct codec for the media file that you are trying to play.
For additional information about verifying, installing, and troubleshooting audio codecs, click the following article numbers to view the articles in the Microsoft Knowledge Base:

142731 How to install and remove codecs and MCI devices in Windows

141801 Troubleshooting audio and video codecs in Windows 95/98

191533 Media Player cannot play .avi file using Indeo 4.x codec

221831 Unable to download the appropriate decompressor

Start Registry Editor and then verify that the following registry subkey and its associated values exist. To start Registry Editor, click Début, click Cours, taper
regedit, and then click d'accord.

Important This section, method, or task contains steps that tell you how to modify the registry. However, serious problems might occur if you modify the registry incorrectly. Therefore, make sure that you follow these steps carefully. For added protection, back up the registry before you modify it. Then, you can restore the registry if a problem occurs. For more information about how to back up and restore the registry, click the following article number to view the article in the Microsoft Knowledge Base:

322756 How to back up and restore the registry in Windows
Registry subkey:

HKEY_CLASSES_ROOTCLSIDInstance Associated entries and their values:


Voir la vidéo: Les fichiers en C: Enregistrer les informations dans un fichier