Initialisation d'un compteur -python
Résolumamiemando Messages postés 33381 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 26 novembre 2024 - 11 avril 2024 à 15:48
- Initialisation d'un compteur -python
- Compteur électrique - Guide
- Comment ralentir un compteur linky forum - Accueil - Objets connectés
- Compteur communicant - Guide
- Citizen code python avis - Accueil - Outils
- Compteur de contractions - Télécharger - Santé & Bien-être
7 réponses
7 avril 2024 à 22:36
Bonjour,
Dans ton programme au tout début tu dois l'initialiser à zéro, à ce moment là affiche le.
7 avril 2024 à 23:42
tu pourrais rajouter un fonction qui affiche la valeur du compteur au départ,
ou tu donnes le source de ton programme pour que l'on jette un oeil
Pour initialiser une variable, il faut écrire:
variable = valeur
et non:
variable == vvaleur
8 avril 2024 à 10:05
hello jee pee -Justement, je ne veux pas de fonction que je devrai ensuite declancher par un bouton ou autre ; Il faut que ce compteur s'initalise de lui meme au demarrage - c est a dire qu'il affiche 0
8 avril 2024 à 10:37
le compteur ne s'initialise pas de lui même, c'est le programme qui le fait, pareil pour l'affichage ;-)
Donne nous un extrait simple de ton code, mais fonctionnel, peut être avec juste la première fonction qui agit sur le compteur.
8 avril 2024 à 15:01
Bonjour,
Il faudrait nous dire ce que tu comptes. Tu risques de devoir passer ton compteur en paramètre de plein de fonctions, ce qui à terme risque d'être lourd.
Variable globale
Une solution simple, mais très sale, consisterait à créer ton compteur en variable globale. Ton programme initialise cette variable globale au démarrage et ensuite tes autres fonctions accèdent à ce compteur.
compteur = 0 def f(): global compteur print("f", compteur) compteur += 1 def g(): global compteur print("g", compteur) compteur += 1 def main(): for _ in range(3): f() for _ in range(2): g() print("compteur", compteur) if __name__ == "__main__": main()
Pourquoi les variables globales sont sales :
- Dans le cas général, on ne sait pas d'où elles proviennent (qui les déclare).
- Leur nom peut entrer en collision avec d'autres variables qui n'ont rien à voir.
- Si on fait de la programmation concurrente, on peut avoir des accès concurrents qui entraînent des effets de bords pernicieux et des bogues difficiles à résoudre.
- Dans d'autres langages que python (ou des versions anciennes de python), l'absence du mot clé global ne permet pas de distinguer les variables globales des variables locales.
Singleton
Une solution plus propre, mais plus compliquée à écrire, consisterait à utiliser un singleton. Un singleton garantit qu'une classe ne peut être instanciée qu'au plus une fois. Si on tente de la ré-instancier, on récupère l'instance déjà existante. Ce serait typiquement le cas de ton compteur.
Cela nous mène par exemple à ce code :
class Singleton(type): """ The :py:class:`Singleton` allows to define singleton classes, i.e. classes that can be instantiated at most once. >>> class MyClass(metaclass=Singleton): pass >>> x = MyClass() >>> y = MyClass() >>> x is y True Based on this `thread <https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python>`__. """ s_instances = dict() def __call__(cls, *args, **kwargs): """ Functor method. Args: cls: The class using the singleton pattern. *args: The args of the class constructor of ``cls``. **kwargs: The kwargs of the class constructor of ``cls``. Returns: The singleton corresponding to ``cls``. """ if cls not in cls.s_instances: cls.s_instances[cls] = ( super(Singleton, cls).__call__(*args, **kwargs) ) return cls.s_instances[cls] class Compteur(metaclass=Singleton): def __init__(self, valeur_initiale: int = 0): print("init") self.compteur = valeur_initiale def __iadd__(self, i: int): self.compteur += i print("iadd", self.compteur) def __int__(self) -> int: return self.compteur def __str__(self) -> str: return str(self.compteur) def f(): compteur = Compteur(0) print("f", compteur) compteur += 1 def g(): compteur = Compteur(0) print("g", compteur) compteur += 1 def main(): for _ in range(3): f() for _ in range(2): g() print("compteur %d" % int(Compteur())) if __name__ == "__main__": main()
Quelques explications :
- La classe Singleton est assez technique, c'est ce qu'on appelle en python une métaclasse. Elle est implémentée ici de sorte à garantir que les classes qui l'exploitent deviennent des singletons.
- Cette classe maintient un dictionnaire qui associe à chaque type estampillé Singleton son instance correspondante, si elle existe déjà en mémoire.
- La méthode __call__ est utilisé pour définir le comportement de l'opérateur (), ici utilisé en interne pour créer une instance de classe estampillée singleton. C'est donc au travers de cette méthode qu'on teste l'existence si pour le type qui nous intéresse, il existe déjà une instance en mémoire. Si c'est le cas, on la retourne. Sinon on la crée et on la retourne.
- La classe Compteur implémente notre compteur. C'est un singleton qui supporte un certain nombre d'opération au travers de ses méthodes :
- __init__ : création du compteur, avec une valeur initiale par défaut de 0
- __iadd__ : support de l'opération +=, pour l'incrémenter
- __str__ : conversion sous forme de chaîne (typiquement via la fonction str(), implicitement utilisée lors d'un appel à la fonction print)
- __int__ : conversion sous forme d'un entier (typiquement via la fonction int())
- On voit que chaque fois qu'on a besoin du compteur, on "crée" le compteur sans se préoccuper de savoir s'il existe ou pas. J'aurais d'ailleurs pu simplement écrire :
compteur = Compteur()
... quand j'en ai besoin, puisque dans __init__, j'ai écrit que la valeur par défaut est 0.
-
Quand on veut incrémenter le compteur, on utilise l'opérateur usuel += (ce qui permet de traverser __iadd__)
-
Quand on veut récupérer la valeur du compteur, on le transforme simplement en entier.
Pourquoi un singleton est préférable
- Pas de risque de collision : la classe est clairement identifiée
- On peut facilement déterminer où la classe est utilisée (voir des outils comme grep)
- On peut facilement modifier le code au niveau de la classe (ici Compteur) pour mettre en place des sections critiques en cas d'accès concurrents.
Compteur d'instance
Dans le cas très particulier où tu veux compter le nombre de fois qu'une classe a été instanciée, il est possible d'avoir un compteur commun à toutes ces instances de classe.
class Personne: compteur = 0 def __init__(self, prenom: str, nom: str): Personne.compteur += 1 self.prenom = prenom self.nom = nom def main(): print(Personne.compteur) # Affiche 0 personne1 = Personne("Luke", "SKywalker") print(Personne.compteur) # Affiche 1 personne2 = Personne("Han", "Solo") print(Personne.compteur) # Affiche 2 if __name__ == "__main__": main()
Bonne chance
8 avril 2024 à 16:53
hello
merci bien de ta réponse
je vais essayer de la comprendre ...
En fait dans un cadre de cryptographie je fais subir à une chaine de caractère une série de fonctions, qui chacune applique un traitement particulier ex : majuscule/minuscule/sans accents/sans ponctuation /concaténation /fractionnement par 5 caracteres ....;Etc ;
A la fin de chaque fonction , je compte le nombre de caracteres que j'envoie a une dernière fonction qui affiche le nombre de caracteres dans un label-- Mais quand je démarre le pgm , aucune chaine de caracteres n'est encore entrée - le programme m'affiche :
"nombre de caracteres = " comment faire pour y mettre un sacré zero "0" au lancement dans la variable qui suit le label ???
Ca a l'air bete , mais tres enervant !
zap
Modifié le 8 avril 2024 à 17:12
Bonjour,
Je vais faire une réponse assez générale puisque tu ne partages pas ton code actuel.
Si tu reprends les solutions que je t'ai proposées :
- Approche avec une variable globale : dans le premier extrait de code que j'ai proposé (voir #8) :
- L'initialisation est clairement faite à la déclaration du compteur.
- L'utilisation (du compteur) nécessite de re-déclarer la variable globale à l'aide du mot clé global (sans quoi python croit que tu parles d'une variable locale qui n'existe pas). Ensuite, tu incrémentes ton compteur de la valeur de ton choix : appeler compteur += i est équivalent à écrire compteur = compteur + i
- Approche avec un singleton : l'initialisation se fait lors de la première construction. L'utilisation est conforme à ce que j'ai expliqué pour l'approche par variable globale.
- La troisième approche ne correspond pas à ton besoin, oublie-la.
Par contre on peut proposer une quatrième approche qui s'en inspire et qui est sans doute la plus indiquée par rapport à ce que tu décris :
- Approche avec un compteur interne à l'instance de classe (self) : Les fonctions dont tu parles ne font pas forcément partie d'une même classe, tu ne peux pas forcément reproduire la même approche. En admettant que tu sois prêt à le réorganiser, ton code ça pourrait ressembler à ceci (et les méthodes f et g font ce que tu veux en plus de mettre à jour le compteur) :
class Encoder: def __init__(self): self.compteur = 0 # Initialisation def f(self): self.compteur += 5 print(encoder.compteur) def g(self): self.compteur += 10 print(encoder.compteur) encoder = Encoder() encoder.f() # Affiche 5 encoder.g() # Affiche 15
Bonne chance
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question8 avril 2024 à 22:26
bonsoir
Je ne rechigne pas a envoyer mon source , y a t il une procedure particuliere ??
en complement de mon explication , il ne s'agit pas d'une incrementation de compteur .
Chaque fonction récupere un string , la manipule . puis je recupere sa longueur "ln"
et je l'expedie a la fonction compte par : compte(ln) .
chaque fonction envoie un nombre different , il y a remplacement et non incrementation
bonne nuit ; j'etudie vos scripts merci
9 avril 2024 à 06:22
Salut,
Puisque l'affichage ce fait dans un label, qu'est-ce qui t'empêche de saisir un texte à la création de celui-ci.
import tkinter as tk root = tk.Tk() label = tk.Label(root, text="Nombre de caractères = 0", width=25) label.pack() root.mainloop()
9 avril 2024 à 23:34
Bonsoir
Oui mais le compteur est updaté a chaque fonction - si on l'ecrit en dur ca ne marche pas -
A la fin de chacune des fonctions de mon pgm je compte le nombre de caraxteres
laz = len ( string) et je l envoie a mon compteur avec l'affichage avec la commande : compte(laz)
===========================
fonction compteur :
def compte(cnt):
Lab3.configure(text="Nombre de caracteres = " + str(cnt) )
voila
10 avril 2024 à 00:05
Même si c'est écrit en dur au moment de l'initialisation de ton label, je ne vois pas pourquoi l'update ne marcherait pas.
import tkinter as tk def compte(cnt): label.configure(text="Nombre de caracteres = " + str(cnt)) root = tk.Tk() label = tk.Label(root, text="Nombre de caractères = 0", width=25) label.pack() compte(100) root.mainloop()
10 avril 2024 à 07:40
Bonjour
au pire
import tkinter as tk def compte(cnt): label.configure(text="Nombre de caracteres = " + str(cnt)) root = tk.Tk() compte(0) label.pack() compte(100) root.mainloop()
10 avril 2024 à 09:25
bonjour,
la procédure pour envoyer une source:
- soit tu cliques sur le bouton "insérer un extrait de code" quand tu tapes une réponse
- soit tu mets ton fichier source à disposition sur Internet, et tu partages un lien vers ce fichier
10 avril 2024 à 15:23
Bonjour
Bonne nouvelle
Mon probleme est resolu par un mix de vos suggestions
Merci a vous tous de votre aide
mik
11 avril 2024 à 15:48
Bonjour, pour rappel, tu peux basculer le sujet en résolu comme expliqué ici.
Bonjour.
Il serait judicieux d'utiliser une variable tkinter si cela est destiné à être un compteur.
Vairiable qui serait partagée par les différentes fonctions.
Exemple très basique :
import tkinter window = tkinter.Tk() for i in range(2): window.columnconfigure(i, weight=1) count = tkinter.IntVar() label = tkinter.Label(window, text="Nombre de caracteres =", font=('', 30)) label.grid(row=0, column=0, sticky=tkinter.E) label = tkinter.Label(window, width=2, textvariable=count, font=('', 30)) label.grid(row=0, column=1, sticky=tkinter.W, padx=(5, 0)) def funct_1(): # pouf +1 count.set(count.get() + 1) def funct_5(): # pouf + 5 count.set(count.get() + 5) def test(): import random for i in range(1, 11): window.after(1000 * i, random.choice((funct_1, funct_5))) test() window.mainloop()
7 avril 2024 à 22:53
bonsoir & merci
oui bien sur , c'est ce je cherche a faire
genre: mon_compteur == 0
Si j initialise au tout debut ; c'est a dire hors fonction , il l'ignore ;
dans les fonctions il n'a rien a y faire ...
a+
8 avril 2024 à 10:29
Par contre, pour l'initialiser à 0, ce n'est pas
mais