Différence entre bouts de codes
Résolu/Fermé
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
-
26 janv. 2022 à 13:53
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 27 janv. 2022 à 12:34
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 27 janv. 2022 à 12:34
A voir également:
- Différence entre bouts de codes
- Codes ascii - Guide
- Différence entre tcp et udp - Guide
- Difference entre million et milliard - Accueil - Technologies
- Comment avoir les codes iptv gratuit forum - Forum Réseaux sociaux
- Différence entre streaming et replay - Guide
5 réponses
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
26 janv. 2022 à 14:33
26 janv. 2022 à 14:33
Bonjour,
Pour toute personne qui tombe sur cette discussion, le code montré est extrait de ce message.
Ici, le code extrait n'a pas de sens seul, car self n'a de sens que si cette variable est défini, ce qui est le cas quand tu travailles dans une classe (le premier paramètre, qui pointe sur l'instance courante de la classe, est noté par convention
Je vais donc supposer que le code est donc plutôt :
code1.py
code2.py
Il y a trois différences, la seconde et la troisième étant conséquence de la première :
Bonne chance
Pour toute personne qui tombe sur cette discussion, le code montré est extrait de ce message.
Ici, le code extrait n'a pas de sens seul, car self n'a de sens que si cette variable est défini, ce qui est le cas quand tu travailles dans une classe (le premier paramètre, qui pointe sur l'instance courante de la classe, est noté par convention
self). Ici le code que tu as extrait de matérialise ni la classe, ni les méthodes, et donc est invalide en tant que tel dans les deux cas. De plus l'indentation, importante en python, n'est pas respectée dans les deux extraits de code que tu reportes.
Je vais donc supposer que le code est donc plutôt :
code1.py
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk class Application: def __init__(self): self.filename = ["{path}image1, {path}image2] self.image_index = 0 self.images = [ tk.PhotoImage(file=f, master=self) for f in filename ] def update_image(self): if self.images: image = self.images[self.image_index] self.canvas_logo.itemconfigure(self.image_container, image=image) self.canvas_logo.pack() def on_update(self): if self.images: self.image_index += 1 self.image_index %= len(self.images) self.update_image() self.after(500, self.on_update)
code2.py
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk class Application: def __init__(self): self.filename = ["{path}image1, {path}image2] self.image_index = 0 def update_image(self): if self.filename: image = tk.PhotoImage(file=filename[self.image_index], master=self) self.canvas_logo.itemconfigure(self.image_container, image=image) self.canvas_logo.pack() def on_update(self): if self.filename: self.image_index += 1 self.image_index %= len(self.filename) self.update_image() self.after(500, self.on_update)
Il y a trois différences, la seconde et la troisième étant conséquence de la première :
- Sous ces conditions, dans
code1.py
la classeApplication
possède un attributself.images
, ce qui n'est pas le cas danscode2.py
. Algorithmiquement parlant c'es la seule différence. - Mais d'un point de vue Tk, il y a une autre différence : pour Tk, les images ne sont pas "chargées" dans le même environnement et donc ton application risque de ne pas afficher correctement les images (voir ce message). C'est pourquoi avec
code2.py
les images risquent de ne pas s'afficher correctement. C'est quelque chose d'assez contre intuitif, de spécifique à la manière dont fonctionne Tk, et qu'il faut "admettre". - Du point de vue de machine, dans
code1.py
les fichiers images sont lus depuis le disque dur une et une seule fois. Ensuite les images sont en mémoire. Danscode2.py
ils sont relus à chaque appel deon_update()
, soit autant de lectures faites sur le disque dur. Si cela est négligeable pour de petits fichiers et une fréquence faible, il faut garder en tête qu'une opération de lecture ou d'écriture est une opération extrêmement lente en informatique (bien plus qu'un accès en mémoire), sans parler du fait tu sollicites davantage ton disque dur (et donc son usure).
Bonne chance
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 26 janv. 2022 à 16:47
Modifié le 26 janv. 2022 à 16:47
Donc le fait de générer directement une double instance de Photoimage ...
En fait ça n'est pas une double instance. Quand tu appelles
Dans mon cas, le dossier
Comme tu peux le voir, les adresses mémoires de chaque image correspond aux adresses mémoires stockées dans
Petite recommandation dans ton code, attention aux pluriels (
Bonne chance
En fait ça n'est pas une double instance. Quand tu appelles
tk.PhotoImage()cela crée une instance en mémoire. Le fait de stocker cette instance dans une liste ne la duplique pas. En réalité, la liste stocke juste une référence vers l'instance existante. La fonction
id()permet de récupérer l'adresse mémoire sous d'une instance. C'est quelque chose que tu peux contrôler dans le constructeur.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk import time import os IMAGE_DIR = "/home/mando/Downloads" def find(dirname :str): return ( os.path.join(root, name) for (root, dirs, files) in os.walk(dirname, topdown=False) for name in files ) class Application(tk.Frame): def __init__(self, filenames=None, master=None): tk.Frame.__init__(self, master) self.pack(expand=True, fill="both") self.entries_y = 30 self.images = list() for filename in filenames: image = tk.PhotoImage(file=filename, master=self if master is None else master) self.images.append(image) print(f"image: {filename} {hex(id(image))}") print(f"self.images: {[hex(id(image)) for image in self.images]}") self.image_index = 0 # [...] root = tk.Tk() root.geometry("1000x720") app = Application( filenames = [ filename for filename in find(IMAGE_DIR) if filename.endswith(".gif") ], master = root ) root.mainloop()
Dans mon cas, le dossier
/home/mando/Downloads/contient 3 fichiers
image1.gif,
image2.gif,
image3.gifet en exécutant ce programme, j'obtiens :
image: /home/mando/Downloads/image3.gif 0x7fbeafd17fd0
image: /home/mando/Downloads/image2.gif 0x7fbeaffe4220
image: /home/mando/Downloads/image1.gif 0x7fbeaffcf7c0
self.images: ['0x7fbeafd17fd0', '0x7fbeaffe4220', '0x7fbeaffcf7c0']
Comme tu peux le voir, les adresses mémoires de chaque image correspond aux adresses mémoires stockées dans
self.images.
Petite recommandation dans ton code, attention aux pluriels (
filename= 1 chemin, donc une chaîne de caractères ;
filenames= plusieurs chaînes de caractères, donc par exemple une liste), idem pour les images. Cela t'évitera de te mélanger les pinceaux :-)
Bonne chance
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
26 janv. 2022 à 15:40
26 janv. 2022 à 15:40
J'espérais que ce soit toi qui me réponde car j'ai pas trouvé mieux en terme d'altruisme.
Tout d'abord dsl pour les indentations, j'ai modifié certaines choses après le copié collé du coup j'ai du merdé à ce moment là. Pour les histoires de self j'aurais du mettre toute la classe directement tu as raison.
Donc le fait de générer directement une double instance de Photoimage et les stocker dans un tableau dès le départ dans le constructeur permet de mémoriser indirectement les images une seule fois pour pouvoir les récupérer quand on veut. Donc dans une classe, si on veut solliciter des fichiers plus tard pour les manipuler, il est préférable de générer des instances avec ces fichiers en arguments, plutôt que de récupérer les fichiers en dur.
Si tu me confirmes mes dires alors grâce à toi j'ai fait un grand pas en avant dans mon apprentissage crois moi..
Tout d'abord dsl pour les indentations, j'ai modifié certaines choses après le copié collé du coup j'ai du merdé à ce moment là. Pour les histoires de self j'aurais du mettre toute la classe directement tu as raison.
Donc le fait de générer directement une double instance de Photoimage et les stocker dans un tableau dès le départ dans le constructeur permet de mémoriser indirectement les images une seule fois pour pouvoir les récupérer quand on veut. Donc dans une classe, si on veut solliciter des fichiers plus tard pour les manipuler, il est préférable de générer des instances avec ces fichiers en arguments, plutôt que de récupérer les fichiers en dur.
Si tu me confirmes mes dires alors grâce à toi j'ai fait un grand pas en avant dans mon apprentissage crois moi..
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
Modifié le 26 janv. 2022 à 17:36
Modifié le 26 janv. 2022 à 17:36
Pardon, bien sûr, quand je disais double instance, c'est deux référence de l' instance , une représentant self.images[0] et une représentant self.images[1] effectivement vu que c'est toujours sur une seule instance self.images . Manque de rigueur de ma part dans mes propos mais j'ai bien compris l'idée du coup. Je suis content d'avoir saisie cette notion maintenant plus qu'à pratiquer encore et encore.
PS: quand j'ai essayé "code2" j'avais bien récupéré l"id de la variable image dans update_image après chaque appel pour voir si ce n' était pas un problème d'adresse mémoire qui se marche dessus. J'ai juste omis volontairement de mettre cette ligne lors de mon post.
Merci énormément encore une fois pour cette masterclass en tout cas. Je déclare le sujet résolu. Bonne soirée :)
PS: quand j'ai essayé "code2" j'avais bien récupéré l"id de la variable image dans update_image après chaque appel pour voir si ce n' était pas un problème d'adresse mémoire qui se marche dessus. J'ai juste omis volontairement de mettre cette ligne lors de mon post.
Merci énormément encore une fois pour cette masterclass en tout cas. Je déclare le sujet résolu. Bonne soirée :)
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 26 janv. 2022 à 17:45
Modifié le 26 janv. 2022 à 17:45
Bonne soirée également :-)
Il est vraiment important de faire le plus tôt possible la distinction entre instance et référence (~ l'adresse mémoire de cette instance). C'est une notion qui revient dans d'autres langages (donc en Java, C++, ...).
En python, les types mutables peuvent être passés par référence à une fonction. Cela concerne la plupart des types (classes, list, set, dict, ...) mais pas les types de bases (int, float) qui sont immutables. Contrairement à d'autres langages (comme le C++ et le Java), les chaînes de caractères sont immutables.
Cela a un impact important. Une fonction peut modifier un paramètre mutable (reçu par référence). S'il reçoit un immutable, tout se passe "comme si" le paramètre était passé par copie.
Exemple : une liste est mutable (= référençable)
Exemple : une chaîne de caractère est immutable :
Bonne chance
Il est vraiment important de faire le plus tôt possible la distinction entre instance et référence (~ l'adresse mémoire de cette instance). C'est une notion qui revient dans d'autres langages (donc en Java, C++, ...).
En python, les types mutables peuvent être passés par référence à une fonction. Cela concerne la plupart des types (classes, list, set, dict, ...) mais pas les types de bases (int, float) qui sont immutables. Contrairement à d'autres langages (comme le C++ et le Java), les chaînes de caractères sont immutables.
Cela a un impact important. Une fonction peut modifier un paramètre mutable (reçu par référence). S'il reçoit un immutable, tout se passe "comme si" le paramètre était passé par copie.
Exemple : une liste est mutable (= référençable)
def f(l): l.append(4) l = [1, 2, 3] f(l) print(l) # [1, 2, 3, 4]
Exemple : une chaîne de caractère est immutable :
def f(s): s += "toto" print(s) # "tatatoto" s = "tata" f(s) print(s) # "tata", pas "tatatoto"
Bonne chance
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
Modifié le 26 janv. 2022 à 19:54
Modifié le 26 janv. 2022 à 19:54
Dans le principe je comprend bien. Après il faut que j'apprenne à utiliser à mon avantage ce principe même suivant les situations. Pour ca il faut que je continue à pratiquer.
Merci beaucoup pour ce rappel.
Ok dans la fonction update_image je peux donc écrire en principe.
Mais j'utiliserai ta méthode en déclarant l'objet directement dans le constructeur c'est plus propre et plus lisible.
Merci beaucoup pour ce rappel.
Ok dans la fonction update_image je peux donc écrire en principe.
def update_image(self): if self.filename: self.image = tk.PhotoImage(file=filename[self.image_index], master=self) self.canvas_logo.itemconfigure(self.image_container, image=self.image)
Mais j'utiliserai ta méthode en déclarant l'objet directement dans le constructeur c'est plus propre et plus lisible.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
27 janv. 2022 à 12:34
27 janv. 2022 à 12:34
Oui, ça devrait marcher, car ce faisant,
selfmaintient une référence vers l'image, que tu pourras ensuite réutiliser dans
on_update.