... | @@ -65,17 +65,21 @@ from tkinter import filedialog as tk_filedialog |
... | @@ -65,17 +65,21 @@ from tkinter import filedialog as tk_filedialog |
|
|
|
|
|
# on crée une fenêtre principale, souvent appelée root ou app
|
|
# on crée une fenêtre principale, souvent appelée root ou app
|
|
root = Tk.Tk()
|
|
root = Tk.Tk()
|
|
root.title("self.titre"fenêtre temporaire")
|
|
root.title("fenêtre temporaire")
|
|
root.protocol('WM_DELETE_WINDOW', self.root.withdraw) # pour empêcher sa fermeture
|
|
root.protocol('WM_DELETE_WINDOW', self.root.withdraw) # pour empêcher sa fermeture
|
|
chemin = tk_filedialog.askopenfilename()
|
|
chemin = tk_filedialog.askopenfilename()
|
|
root.destroy() # on détruit la fenêtre
|
|
root.destroy() # on détruit la fenêtre
|
|
|
|
|
|
```
|
|
```
|
|
|
|
|
|
Si on utilise plusieurs fois les méthodes de filedialog, on propose de créer un "context manager" pour insérer des actions avant et après le bloc de code. La notion de context manager sort du cadre de ce premier atelier, même si on l'utilise pour ouvrir un ficher avec **with open() as...**. L'idée est de définir dans une classe ad-hoc ce que l'on fait avant et après l'exécution du bloc de code, dans les méthodes __enter__ et __exit__.
|
|
Si on utilise plusieurs fois les méthodes de filedialog, on propose de créer un "context manager" pour insérer des actions avant et après le bloc de code. La notion de context manager sort du cadre de ce premier atelier, même si on l'utilise pour ouvrir un ficher avec **with open() as...**. Ce qui suit est donc facultatif, au pire retenez que ça existe et vous y reviendrez quand vous en aurez besoin
|
|
Cette notion est également pratique dans une classe "normale" pour définir des actions à la création et à la destruction d'une instance.
|
|
|
|
|
|
|
|
<details><summary>un exemple simple de context manager</summary>
|
|
* * * début de l'aparté sur les context managers appliqués aux méthodes de filedialog * * *
|
|
|
|
L'idée est de définir dans une classe ad-hoc ce que l'on fait avant et après l'exécution du bloc de code, dans les méthodes __enter__ et __exit__.
|
|
|
|
Cette notion est également pratique dans une classe "normale" pour définir des actions à la création et à la destruction d'une instance, si on le fait au sein d'un bloc introduit par with.
|
|
|
|
|
|
|
|
```python
|
|
|
|
# un exemple simple de context manager pour tester
|
|
class UnObjetPourTester:
|
|
class UnObjetPourTester:
|
|
def __init__(self, nom="un objet", poubelle ="grise"):
|
|
def __init__(self, nom="un objet", poubelle ="grise"):
|
|
self.nom = nom
|
|
self.nom = nom
|
... | @@ -86,13 +90,51 @@ class UnObjetPourTester: |
... | @@ -86,13 +90,51 @@ class UnObjetPourTester: |
|
|
|
|
|
def __exit__(self, exc_type, exc_value, tb):
|
|
def __exit__(self, exc_type, exc_value, tb):
|
|
print(f'Destruction de {self.nom} ; hop dans la poubelle {self.poubelle}.')
|
|
print(f'Destruction de {self.nom} ; hop dans la poubelle {self.poubelle}.')
|
|
|
|
return False # False => mon exception va être remontée (bonne pratique)
|
|
|
|
|
|
|
|
print("tests de la notion de context manager")
|
|
|
|
# sans context manager
|
|
|
|
papier_gras = UnObjetPourTester("papier gras", "grise")
|
|
|
|
del(papier_gras)
|
|
|
|
# dans le cadre d'un context manager
|
|
|
|
with UnObjetPourTester("bouteille d'eau", "verte") as bouteille_eau:
|
|
|
|
del(bouteille_eau)
|
|
|
|
```
|
|
|
|
L'exemple ci-dessus écrit dans la console:
|
|
|
|
> tests de la notion de context manager
|
|
|
|
Création de bouteille d'eau.
|
|
|
|
Destruction de bouteille d'eau ; hop dans la poubelle verte.
|
|
|
|
|
|
|
|
Les actions définies par __enter__ et __exit__ ne sont exécutées que dans le second cas.
|
|
|
|
En s'appuyant sur cette notion, on a proposé le script suivant pour gérer la création et la destruction de la fenêtre encadrant l'appel à une méthode de filedialog.
|
|
|
|
|
|
|
|
```python
|
|
|
|
# application de la notion de context manager pour utiliser filedialog
|
|
|
|
class FenetrePourDialogue:
|
|
|
|
def __init__(self, titre="fenêtre temporaire"):
|
|
|
|
self.titre = titre
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
print(f'Opening {self.titre}.')
|
|
|
|
self.root = Tk.Tk()
|
|
|
|
self.root.title(self.titre)
|
|
|
|
# on empêche la fermeture intempestive de la fenêtre par l'utilisateur
|
|
|
|
self.root.protocol('WM_DELETE_WINDOW', self.root.withdraw)
|
|
|
|
|
|
|
|
def __exit__(self,exc_type, exc_value, tb):
|
|
|
|
print(f'Closing {self.titre}.')
|
|
|
|
if self.root:
|
|
|
|
self.root.destroy()
|
|
return False # False => mon exception va être remontée (bonne pratique)
|
|
return False # False => mon exception va être remontée (bonne pratique)
|
|
|
|
|
|
</details>
|
|
with FenetrePourDialogue() as fenetre:
|
|
|
|
chemin = tk_filedialog.askopenfilename()
|
|
|
|
print(chemin)
|
|
|
|
```
|
|
|
|
|
|
|
|
* * * fin de l'aparté sur les context managers appliqués aux méthodes de filedialog * * *
|
|
|
|
|
|
Là encore, il est utile de vérifier si le fichier existe.
|
|
Dans tous les cas, il est utile de vérifier si le fichier existe.
|
|
Il n'est pas rare d'avoir des problèmes de format ; sur le REPL.IT vous trouverez deux fichiers dont le nom commence par "B2220010" ; un seul permet de faire tourner le code correctement. Si vous les ouvrez, vous ne verrez pas de différence au premier abord. Celui qui est déposé sur le gitlab a été d'abord copié sur le site REPL, mais le code ne pouvait pas l'ouvrir... On a "truandé" en ouvrant un fichier sur le REPL puis en copiant-collant les données dedans...
|
|
Il n'est pas rare d'avoir des problèmes de format ; sur le REPL.IT vous trouverez deux fichiers dont le nom commence par "B2220010" ; un seul permet de faire tourner le code correctement. Si vous les ouvrez, vous ne verrez pas de différence au premier abord. Celui qui est déposé sur le gitlab a été d'abord copié sur le site REPL, mais le code ne pouvait pas l'ouvrir... On a "truandé" en ouvrant un fichier sur le REPL puis en copiant-collant les données dedans...
|
|
Si vous avez un Mac vous pourriez être amené à pratiquer le même genre de bidouille ou bien à rechercher le format du fichier d'entrée.
|
|
Si vous avez un Mac vous pourriez être amené à pratiquer le même genre de bidouille ou bien à rechercher le format du fichier d'entrée.
|
|
|
|
|
... | @@ -103,9 +145,13 @@ Sur les deux supports, un code vous est déjà proposé. |
... | @@ -103,9 +145,13 @@ Sur les deux supports, un code vous est déjà proposé. |
|
Pratique recommandée pour ouvrir un fichier : "**with** open(nom_fichier, 'r') as alias_du_fichier".
|
|
Pratique recommandée pour ouvrir un fichier : "**with** open(nom_fichier, 'r') as alias_du_fichier".
|
|
|
|
|
|
:baby: Si vous débutez : retenez que cette syntaxe est fortement recommandées ; si vous utilisez une autre façon de faire vous devrez bien penser à fermer le fichier à la fin.
|
|
:baby: Si vous débutez : retenez que cette syntaxe est fortement recommandées ; si vous utilisez une autre façon de faire vous devrez bien penser à fermer le fichier à la fin.
|
|
:older_man: Si vous être plus avancé, vous connaissez peut-être la notion de **context manager**.
|
|
:older_man: On a mentionné plus haut la notion de **context manager**.
|
|
|
|
|
|
|
|
<details><summary>un autre petit mot facultatif sur les context managers et les décorateurs </summary>
|
|
=> **with** introduit un **"context manager"** qui déclenche une action définie par la méthode dunder __start__ de la classe avant la première instruction, et une dernière action définie par la dunder __end__ à la fin. Ici, l'action finale est la fermeture du fichier, ce qui garantit que le fichier se fermera à la fin du bloc d'instructions, quoi qu'il arrive. Cela rappelle les décorateurs, sauf qu'ici on peut choisir d'appeler au cas par cas la classe avec un context manager ou pas, alors que les décorateurs modifient définitivement la fonction (surcharge).
|
|
=> **with** introduit un **"context manager"** qui déclenche une action définie par la méthode dunder __start__ de la classe avant la première instruction, et une dernière action définie par la dunder __end__ à la fin. Ici, l'action finale est la fermeture du fichier, ce qui garantit que le fichier se fermera à la fin du bloc d'instructions, quoi qu'il arrive. Cela rappelle les décorateurs, sauf qu'ici on peut choisir d'appeler au cas par cas la classe avec un context manager ou pas, alors que les décorateurs modifient définitivement la fonction (surcharge).
|
|
On peut par exemple définir un context manager pour mesurer le temps d'exécution d'une fonction (au début : on note l'heure ; à la fin : on note l'heure et on calcule le délai).
|
|
On peut par exemple définir un context manager pour mesurer le temps d'exécution d'une fonction (au début : on note l'heure ; à la fin : on note l'heure et on calcule le délai).
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
|
Une fois le fichier ouvert, on va lire les lignes avec alias_du_fichier.readline().
|
|
Une fois le fichier ouvert, on va lire les lignes avec alias_du_fichier.readline().
|
|
Dans le code proposé, on va d'abord lire les lignes une à une jusqu'à en trouver une qui contienne un mot-clé.
|
|
Dans le code proposé, on va d'abord lire les lignes une à une jusqu'à en trouver une qui contienne un mot-clé.
|
... | | ... | |