IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Globales en Python.


Sujet :

Python

  1. #1
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut Globales en Python.
    Bonjour à tous ...
    Petite question, pas vraiment existentielle, mais qui sait ?
    Je travaille sur un projet (un jeu, en fait) et j'ai une bonne cinquantaine de variables globales. Tout ce beau monde est logé dans un dictionnaire que je sauve dans un fichier en quittant le jeu de façon à pouvoir le reprendre plus tard. C'est ce dictionnaire que je passe en paramètre aux fonctions ou procédures qui vont avoir besoin d'une partie de son contenu. Après d'éventuelles modifications au dico, les fonctions me le retournent " updaté ".
    J'ai opté pour cette solution car j' espère que tant qu'un script s'exécute, une modification de dictionnaire n'entraine pas une écriture sur le disque dur. Ainsi, je n'ai qu'à sauver le dictionnaire dans un fichier quand je quitte le script.
    Selon vous, est-ce là une bonne méthode pour gérer les variables globales, ou y-a-t-il mieux ?
    Ha, tout de même : le jeu en lui-même, n'est pas gourmand en ressources et la vitesse n'est absolument pas quelque chose de crucial.
    Merci, beaucoup de vos réponses.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Tout d'abord, si les variables sont globales, pourquoi les passes-tu en paramètre à tes fonctions qui les connaissent déjà (définition basique d'une globale) ?
    Ceci dit, les globales sont rarement une bonne idée car elles posent plus de souci qu'elles n'en résolvent, le premier étant le nom à trouver pour chacune (tu l'as d'ailleurs compris puisque tu mets ça dans un dico) et un autre étant que ça casse l'indépendance des fonctions (une fonction étant censée pouvoir travailler de façon isolée ce qui n'est pas possible si elle utilise une variable qui ne lui appartient pas). Bref dans le monde de la programmation structurée, les globales c'est mal.

    Concernant la sauvegarde des paramètres (ce qu'on nomme généralement la "configuration") d'un programme j'ai déjà eu ce souci (exemple login, mot de passe, adresse du serveur, etc) que j'ai résolu en passant par les fichiers ".ini" bien connu du monde Windows (ou ".rc" dans le monde Linux).
    J'ai donc créé un objet "config" qui contient en différents attributs tous les éléments de configuration du programme. Cet objet config, au lancement du programme, va lire le ".ini" précédemment sauvegardé et charge ainsi tous les paramètres. Si premier lancement (ou si pas de ".ini") alors le projet contient un ".ini" par défaut qui est chargé à sa place. Et en plus l'objet contient aussi des valeurs par défaut pour chaque paramètre donc en réalité il y a 3 niveaux de config
    • chargement des valeurs par défaut de l'objet (que seul le créateur du programme, donc moi, peut modifier)
    • chargement du .ini global du projet (modifiable par l'admin machine)
    • chargement du .ini de l'utilisateur (modifiable par l'utilisateur)

    Et quand le programme se termine, il écrit le ".ini" dans le dossier de l'utilisateur. Donc c'est presque comme toi. Sauf que l'objet config n'étant pas global, il est alors passé à tous les autres objets du programme qui ainsi ont accès à la configuration.

    Et surtout Python possède une librairie "configparser" dédiée à lire et écrire les ".ini".

    Donc oui, ton idée est bonne, il lui manque juste l'expérience.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour

    +1 pour les fichiers ini que j'utilise beaucoup pour conserver des données d'une cession à l'autre.

    Il y a un avantage: on peut intervenir directement sur le fichier ini entre 2 cessions pour modifier certaines données avec un simple éditeur de texte. L'inconvénient est sa contrepartie: on ne peut stocker que des valeurs "imprimables".

    Une autre solution, les modules dits de "sérialisation" comme pickle. En ce que concerne, je préfère shelve (https://docs.python.org/fr/3/library...#module-shelve). On peut ainsi stocker directement un dictionnaire d'objets python, et le recharger en retrouvant les données avec leurs types (int, str, list, dict, ...).

    Voilà un petit exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    import shelve
     
    # objets a sauvegarder sur disque et à recuperer
    L0 = True
    L1 = 123456
    L2 = 1.789e5
    L3 = complex(1,2)
    L4 = "ABC"
    L5 = 'DEF'
    L6 = [L0, L1, L2, L3, L4, L5]
    L7 = (L0, L1, L2, L3, L4, L5)
    L8 = {'L0':L0, 'L1':L1, 'L2':L2, 'L3':L3, 'L4':L4, 'L5':L5, 'L6':L6}
    L9 = set([L0, L1, L2, L3, L4, L5])
     
    # sauvegarde des objets
    with shelve.open('dicoconfig') as d:
        d['L0'] = L0
        d['L1'] = L1
        d['L2'] = L2
        d['L3'] = L3
        d['L4'] = L4
        d['L5'] = L5
        d['L6'] = L6
        d['L7'] = L7
        d['L8'] = L8
        d['L9'] = L9
     
    # récupération des objets sauvegardés
    with shelve.open('dicoconfig') as d:
        R0 = d['L0']
        R1 = d['L1']
        R2 = d['L2']
        R3 = d['L3']
        R4 = d['L4']
        R5 = d['L5']
        R6 = d['L6']
        R7 = d['L7']
        R8 = d['L8']
        R9 = d['L9']
     
    # affichage des objets récupérés
    print("objets recuperes par shelve:") 
    print(R0, type(R0))
    print(R1, type(R1))
    print(R2, type(R2))
    print(R3, type(R3))
    print(R4, type(R4))
    print(R5, type(R5))
    print(R6, type(R6))
    print(R7, type(R7))
    print(R8, type(R8))
    print(R9, type(R9))
    print()
    Ce qui affiche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    objets recuperes par shelve:
    True <class 'bool'>
    123456 <class 'int'>
    178900.0 <class 'float'>
    (1+2j) <class 'complex'>
    ABC <class 'str'>
    DEF <class 'str'>
    [True, 123456, 178900.0, (1+2j), 'ABC', 'DEF'] <class 'list'>
    (True, 123456, 178900.0, (1+2j), 'ABC', 'DEF') <class 'tuple'>
    {'L0': True, 'L1': 123456, 'L2': 178900.0, 'L3': (1+2j), 'L4': 'ABC', 'L5': 'DEF', 'L6': [True, 123456, 178900.0, (1+2j), 'ABC', 'DEF']} <class 'dict'>
    {123456, True, (1+2j), 178900.0, 'DEF', 'ABC'} <class 'set'>
    Ce code enregistre 2 fichiers: dicoconfig.dat et dicoconfig.dir

    On voit que c'est très facile à faire, et on récupère bien les objets dans leurs types. La contrepartie ici est que le fichier n'est pas consultable ni modifiable entre 2 cessions avec un éditeur de texte.

    Comme c'est marqué dans la doc, la seule réserve est celle de la sécurité si on voulait charger un fichier shelve d'origine inconnue, car il pourrait comporter des codes "indésirables".

  4. #4
    Membre Expert
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2003
    Messages
    1 603
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 603
    Par défaut
    Je plussois pour le fichier .ini, même si j'ai une préférence pour davantage utiliser un fichier YAML ou JSON.

    Et si dans tes variables globales, il y en a qui ne changent jamais de valeur, tu pourrais aussi les utiliser comme variables d'environnement.

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 714
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 714
    Par défaut
    Citation Envoyé par azad2b Voir le message
    Selon vous, est-ce là une bonne méthode pour gérer les variables globales, ou y-a-t-il mieux ?
    Techniquement, ces variables représentent l'état global de l'application et comme cet état est sauvegardé dans un fichier disque, on dira qu'il "persiste" d'une activation à l'autre.
    Ce ne sont pas des variables globales "python" (sauf peut être pour le dictionnaire).

    Si on veut faire "mieux" côté organisation du code, peut être faudrait-il segmenter/classer ces 50 variables en sous ensembles cohérents avec certaines fonctions (chaque fonction n'a pas besoin de lire / écrire toutes ces variables).
    Ces sous ensembles pourraient être des dictionnaires (l'état global serait alors un dictionnaire de dictionnaires et on passe le(s) sous-dictionnaires intéressants au fonctions qui...)... ou des instances de classes (créées avec les valeurs du fichier qui les contient).

    Après côté stockage de l'état dans des fichiers, il faut distinguer les données qui pourront être modifiées par l'utilisateur (le nom d'un répertoire de travail par exemple) de celles qui doivent rester sous le contrôle du programme.... et les stocker dans des fichiers au format ad hoc (un .ini pour les variables utilisateurs) un fichier JSON (dict de dicts) ou pickle/shelve pour des instances d'objets Python.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Bonjour
    Tout d'abord, et pour répondre à wistricks, que je salue, j'avais un peu simplifié les choses, et en fait ce n'est pas un dico que j'utilise, mais trois. Ils contiennent chacun les variables rangées selon leurs utilisations potentielles. Cela me permet de ne passer aux fonctions que le dico contenant ce qu'elles attendent.
    Cela étant et après avoir lu les conseils de Sve@r et de tyrtamos j'ai fini par admettre que certaines notions "Python" m'étaient totalement inconnues. Au hasard de mes lectures, je les avais croisées souvent ... mais toujours ignorées. Par exemple les fichiers INI et JSON, m'avaient tentées, puis ... rebutées. Le résultat c'est que beaucoup de mes fonctions comportent de longues litanies de "global a,b,....,y,z" et même sans vouloir à tout prix être élégant, je reconnais que c'est très désagréable à voir.
    A propos : tyrtamos ta méthode de sauvegarde/lecture de fichier sans utiliser la gestion des fichiers traditionelle, m'a tapé dans l'oeil. J'ai tout à apprendre...
    Je vais donc me résigner à tenter de m'instruire en utilisant vos suggestions. Mais ne vous y trompez pas ! Je risque de revenir.
    Ha, au fait, histoire de faire connaissance. J'utilise un "gros" MacPro (genre 25 kg d'aluminium) mais sans MacOS. (remplacé par un Linux moins bling bling) et j'ai beau être encore accroc à l'électronique, qui fut mon métier et reste ma passion, le fait que j'ai largué Apple et sa ToolBox m'interdit de programmer des choses avec XCode que je connaissais. Et c'est pourquoi je me suis rabattu sur Python depuis peu. Et comme je suis né en 1937, soyez cléments si je semble un peu dur d'oreille.
    Merci à vous.

  7. #7
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 321
    Par défaut
    bonjour

    Comme wiztricks ...

    Tu sembles n'avoir qu'un objet global mais JAMAIS utilisé directement. Donc aucun problème, qu'il soit global ou local à une fonction main() par exemple est anecdotique.

    Citation Envoyé par azad2b Voir le message
    mes fonctions comportent de longues litanies de "global a,b,....,y,z" et même sans vouloir à tout prix être élégant, je reconnais que c'est très désagréable à voir.
    je passe en paramètre aux fonctions ou procédures
    ?? tu te contredis ? ici il n'est surtout pas une question d'élégance ! cela donne un code "infernal" : non maintenable et extrêmement compliqué (à comprendre son cheminement), donc le meilleur moyen de pondre des bugs et d'attraper des maux de tête. C'est un château de verre avec des fondations en allumettes. Dans ce cas, c'est direction poubelle

    ---------

    Pour le format de fichier, oui json est le plus simple/souple pour le codeur. Mais il faut l'exclure si l'utilisateur peut l'éditer manuellement car ce format est beaucoup trop stricte.
    Note: avec la dernière version python 3.11, nous avons toml inclus. Ce format est un .ini étendu et donne justement une souplesse plus proche de json.

  8. #8
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    @papajoker. Bonjour
    Exemple réel. J'ai un dico nommé dicoStat. Je le sauve quand je quitte mon script sur le disque dur. Mais tant que le script est actif si l'une des fonction en a modifié une des valeurs, il est sauvé dans le répertoire ramdisk (que j'ai créé dans le répertoire mnt) . A l'allumage de l'ordinateur, le fichier fstab est lu et le ramdisk est créé, puis une fonction va vérifier si dicoStat existe en Ram et si ce n'est pas le cas ( cas ou l'on vient de lancer le script), va le lire sur le DD pour le recopier en Ram.
    Voici la structure du dictionnaire et la fonction qui l'écrit (en DD ou en Ram)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {'contexte': 1, 'credit': 18.0, 'bet': 2.0, 'cIN': 50, 'cOUT': 0, 'cBET': 6.0, 'cGAIN': 18.0, 'coups_joues': 3, 'autoHold': True}
    def ecritStat(x,dicoStat):
        if x == 'RAM':
            f = open('//mnt/ramdisk/stat', 'wb')
        else:
            f = open('stat','wb')
        dump(dicoStat['contexte'], f)
        dump(dicoStat['credit'], f)
        dump(dicoStat['bet'], f)
        dump(dicoStat['cIN'], f)
        dump(dicoStat['cOUT'], f)
        dump(dicoStat['cBET'], f)
        dump(dicoStat['cGAIN'], f)
        dump(dicoStat['coups_joues'], f)
        dump(dicoStat['autoHold'], f)
        f.close()
    Supposons maintenant que j'appelle une fonction mise() qui va lire la valeur de bet et qui va donc calculer le résultat de credit-bet. et incrémenter la valeur de cBET et celle de coups_joues.
    Il faut bien que je passe à la fonction mise quelques informations ! Par exemple il existe une mise maximale autorisée, on ne peut pas miser plus que le crédit dont on dispose, etc....
    Donc si je ne passe pas dicoStat intégralement à mise() je suis bien obligé de déclarer pour le moins dicoStat en global dans mise. Sinon je lui passe au moins les valeurs de bet, de cBET et de credit (cBET est la somme de toutes les mises)
    Comment ferais-tu, toi ?
    Bon vous avez compris, il s'agit d'un vidéo-Poker. Mais très sophistiqué car il y a un Joker dans le jeu. Dans son état actuel il est parfaitement fonctionnel et même assez élégant à regarder (mais son code et franchement dégueulasse) et j'ai l'intention de l'offrir (avec nettoyage) aux gens intéressés ici.

  9. #9
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 321
    Par défaut
    Il faudrait nous dire si tu utilises un framework ... la structure du programme peut-être complètement différente (forcée par le framework)

    si tu as le dico
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    parametres["application"]
    parametres["jeu"]
    parametres["jeu"]["joueur"]
    Tu peux très bien passer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    def main():
       parametres = charger_fichier_config("toto.conf")
       ...
       evaluer_la_main(1,2, parametres["jeu"])
      # ou parametres["jeu"]["xxx"] = evaluer_la_main(1,2, parametres["jeu"])
     
    def evaluer_la_main(x,y, parametres_jeu):
    Python passe l'objet par référence, cela signifie qu'il ne passe qu'un "pointeur", ce paramètre est donc en mémoire extrêmement léger


    Nom de variable "dicoStat" ! on ne donne pas le type dans le nom ! Et le nom doit tout dire du contenu (ex: statistiques_joueur, statistiques_table)

    ------------
    Rien compris au résonnement "ram" - avoir à faire une modif dans etc/fstab
    Ici, tu ne fais que dupliquer (en ram) ta variable globale "parametres", pourquoi ne pas simplement la sauvegarder à la sortie du programme ? A la limite, si vraiment utile, alors juste faire un lien symbolique dans /tmp/ vers le fichier ?
    ps: et le format du fichier ... json est ton ami

    Et tu es sous linux ... "open('stat','wb')" beurk, "/home/$USER/.local/share/pocker/stat.json" (.local/share/ et/ou .config/)

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 714
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 714
    Par défaut
    Citation Envoyé par azad2b Voir le message
    Donc si je ne passe pas dicoStat intégralement à mise() je suis bien obligé de déclarer pour le moins dicoStat en global dans mise. Sinon je lui passe au moins les valeurs de bet, de cBET et de credit (cBET est la somme de toutes les mises)
    Comment ferais-tu, toi ?
    dicoStat est un dictionnaire. Un dictionnaire est "mutable": pas besoin de le déclarer global à l'entrée d'une fonction pour en modifier les clefs/valeurs ni même de le passer en paramètre à l'appel de la fonction si la variable dicoStat est "globale" (au sens Python du terme).

    Une fonction n'existe pas toute seule dans son coin, il faut qu'on l'appelle depuis un endroit du programme avec les arguments nécessaires et qu'elle retourne quelque chose dont l'appelant fera un peu ce qu'il veut.
    Le truc un peu magique là dedans (et qui semble être inutile) est que la fonction ignore d'où l'appelant a récupéré ces paramètres ni de ce qu'il fera du résultat: en gros dicoStat n'existe pas pour la fonction.

    Là encore on "classifie"/hiérarchise entre les fonctions qui accèdent à dicoStat et celles qui bossent pour elles sans trop savoir d'où sortent les données.

    Ceci dit, ce travail "d'organisation" ne va pas changer grand chose au fonctionnement du jeu mais facilitera peut être la lecture/maintenance/ajout de fonctionnalités (c'est par là que sera le "mieux").

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par azad2b Voir le message
    A l'allumage de l'ordinateur, le fichier fstab est lu et le ramdisk est créé, puis une fonction va vérifier si dicoStat existe en Ram et si ce n'est pas le cas ( cas ou l'on vient de lancer le script), va le lire sur le DD pour le recopier en Ram.
    Pourquoi faire ??? Sauvegarder un état sur dd ok, cela permet de le récupérer lors du lancement suivant mais pourquoi le sauver sur ramdisk ??? Le ramdisk se comporte exactement comme un disque hormis qu'il se trouve en RAM (donc perdu si l'ordi s'arrête). Mais entre "sauver un dico sur ramdisk puis le récupérer dans chaque fonction qui en a besoin" et "garder le dico en RAM du programme et le passer aux fonctions qui en ont besoin" il n'y a aucune différence... sauf les opérations de "lecture fichier depuis le disque" qui restent des opérations "en plus" donc inutiles.
    En plus simple: j'ai besoin d'une variable "prix", j'écris dans mon code prix=10 puis je passe cette variable "prix" aux fonctions qui en ont besoin. Je ne m'embête pas à sauver ce prix sur disque (qu'il soit physique ou ram) pour le récupérer depuis mes fonctions (sans parler du crash qui se passera si on applique cette procédure "sauvegarde/récupération" dans une fonction récursive !!!!!!).
    Bref les étapes "sauvegarde sur disque et/ou récupération" doivent être des étapes rares, appliquées seulement quand le programme démarre ou se termine. On peut éventuellement offrir à l'utilisateur un choix "enregistrement sur demande" mais pas plus.

    Citation Envoyé par azad2b Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def ecritStat(x,dicoStat):
        if x == 'RAM':
            f = open('//mnt/ramdisk/stat', 'wb')
        else:
            f = open('stat','wb')
        dump(dicoStat['contexte'], f)
        dump(dicoStat['credit'], f)
        dump(dicoStat['bet'], f)
        dump(dicoStat['cIN'], f)
        dump(dicoStat['cOUT'], f)
        dump(dicoStat['cBET'], f)
        dump(dicoStat['cGAIN'], f)
        dump(dicoStat['coups_joues'], f)
        dump(dicoStat['autoHold'], f)
        f.close()
    Pour sauvegarder seulement certains items de dicoStat...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def ecritStat(fic, dicoStat):
    	with open(fic, "wb") as fp:
    		for k in (
    			"contexte",
    			"credit",
    			"bet", 
    			...
    			"autoHold",
    		): dump(dicoStat[k], fp)
    Pour sauvegarder tout dicoStat (si on veut pas passer par pickle qui est quand-même fait pour ça)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def ecritStat(fic, dicoStat):
    	with open(fic, "wb") as fp:
    		for v in dicoStat.values(): dump(v, fp)
    Et à l'appel de ta fonction tu lui passes le nom du fichier ("/mnt/ramdisk/stat" ou "stat" ou ce que tu veux). Bref comme le dit Wiztricks, ce n'est pas à la fonction de se préoccuper de son environnement (si le truc est en ramdisk ou simple disque). Son job est de sauvegarder sur fichier, on lui passe le fichier (d'ailleurs tu as remarqué, je ne me suis même pas préoccupé de la fonction dump(), son rôle étant visiblement de dumper un truc sur un fichier, je suis parti du principe qu'elle fonctionnait donc je l'ai simplement utilisée)

    Citation Envoyé par azad2b Voir le message
    Supposons maintenant que j'appelle une fonction mise() qui va lire la valeur de bet et qui va donc calculer le résultat de credit-bet. et incrémenter la valeur de cBET et celle de coups_joues.
    Il faut bien que je passe à la fonction mise quelques informations ! Par exemple il existe une mise maximale autorisée, on ne peut pas miser plus que le crédit dont on dispose, etc....
    Donc si je ne passe pas dicoStat intégralement à mise() je suis bien obligé de déclarer pour le moins dicoStat en global dans mise. Sinon je lui passe au moins les valeurs de bet, de cBET et de credit (cBET est la somme de toutes les mises)
    Comment ferais-tu, toi ?
    Soit je lui passe uniquement ce dont elle a besoin (mise maximale, crédit etc), ce qui est l'attitude la plus propre mais la plus lourde (faut tout réfléchir), soit je ne m'embête pas et lui passe mon objet "config" et elle y récupère ce dont elle a besoin. Sans avoir dans les deux cas besoin de globale.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Décidément je ne regrette pas d'avoir posté cette question ici. Je ne reçois que des remarques très constructives. J'en tiens compte "à la volée " et je constate qu'elles sont toutes très judicieuses. Et si cela ne fait que justifier mes réticences par rapport à Python, que je juge trop permissif par rapport à un Pascal dictatorial ou un C tyrannique, ce n'est pas parce que je suis masochiste .... c'est parce que ces langages (tout comme objectiveC) m'ont trop marqués jadis. Rien qu'avec ce que j'ai appris entre hier et aujourd'hui va m'occuper au moins jusqu'à 3 h du matin, rien qu'en corrections et en élagage, un peu partout.
    Merci à vous tous.

  13. #13
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Citation Envoyé par papajoker Voir le message
    Il faudrait nous dire si tu utilises un framework ... la structure du programme peut-être complètement différente (forcée par le framework)

    si tu as le dico
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    parametres["application"]
    parametres["jeu"]
    parametres["jeu"]["joueur"]
    Tu peux très bien passer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    def main():
       parametres = charger_fichier_config("toto.conf")
       ...
       evaluer_la_main(1,2, parametres["jeu"])
      # ou parametres["jeu"]["xxx"] = evaluer_la_main(1,2, parametres["jeu"])
     
    def evaluer_la_main(x,y, parametres_jeu):
    Python passe l'objet par référence, cela signifie qu'il ne passe qu'un "pointeur", ce paramètre est donc en mémoire extrêmement léger


    Nom de variable "dicoStat" ! on ne donne pas le type dans le nom ! Et le nom doit tout dire du contenu (ex: statistiques_joueur, statistiques_table)

    ------------
    Rien compris au résonnement "ram" - avoir à faire une modif dans etc/fstab
    Ici, tu ne fais que dupliquer (en ram) ta variable globale "parametres", pourquoi ne pas simplement la sauvegarder à la sortie du programme ? A la limite, si vraiment utile, alors juste faire un lien symbolique dans /tmp/ vers le fichier ?
    ps: et le format du fichier ... json est ton ami

    Et tu es sous linux ... "open('stat','wb')" beurk, "/home/$USER/.local/share/pocker/stat.json" (.local/share/ et/ou .config/)
    Ben ... tu as probablement raison, mais en quoi dire que je vais écrire un fichier binaire est-il choquant ? Je ne fais pas partie de ces gens qui prennent leur pied quand ils ont réussi à économiser une frappe au clavier. Mais les fichiers JSON sont pour moi, de parfaits inconnus. Je vais m'y mettre demain et qui sait ? il en sortira peut-être quelque chose. Pour le reste et en particulier l'utilisation de la RAM c'est différent et cela relève de ma spécialité : un montage "mobile" alimenté par des piles ou des accumulateurs, n'est pas un truc qui dépend d' EDF. Un Ramdisk diminue de façon spectaculaire l'énergie consommée. donc l'autonomie.
    Au fait, pas de framework. Je n'utilise dans mon GUI pratiquement que Tkinter.

  14. #14
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 321
    Par défaut
    Citation Envoyé par azad2b Voir le message
    Mais les fichiers JSON sont pour moi, de parfaits inconnus.
    Mais ici tu fais du json avec ton dump() json c'est la représentation texte de tes objets (print(dicoStat))

    Citation Envoyé par azad2b Voir le message
    Un Ramdisk augmente de façon spectaculaire l'énergie consommée. donc l'autonomie.
    Mais quand sauvegardes-tu ? Aucune raison de sauver au milieu sauf si tu attends un plantage du programme ... même là, il est possible de sauver dans le fichier.
    Et si tu ne sauvegardes qu'a la fin, il faut bien copier le fichier en ram sur le disque (donc aucun gain!)

    Citation Envoyé par azad2b Voir le message
    Au fait, pas de framework. Je n'utilise dans mon GUI pratiquement que Tkinter.
    Tkinter est un framework et comme il est événementiel, la structure du code est très particulière, donc c'est très important

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par azad2b Voir le message
    Je ne fais pas partie de ces gens qui prennent leur pied quand ils ont réussi à économiser une frappe au clavier.
    Ce n'est pas tout à fait notre objectif non plus. On cherche plutôt à concilier l'efficacité avec l'évolutivité (penser à ce que pourrait devenir le programme demain) avec la facilité de maintenance (quand la config est enregistrée dans un fichier texte, c'est plus facile de la vérifier, voire la réparer si elle a mal été enregistrée).

    Citation Envoyé par azad2b Voir le message
    Mais les fichiers JSON sont pour moi, de parfaits inconnus.
    Ils sont sympas, pas compliqués à comprendre, mais peut-être pas faits pour quelque chose d'aussi simple qu'une config. Ils peuvent gérer mais ça me donne l'impression d'utiliser une presse hydraulique pour presser une orange.
    Parce qu'entre...
    Code ini : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [bdd/administration]
    user=toto
    password=123
    host=/tmp
    port=5432
     
    [joueur/parametrage]
    bet=10
    miseMax=100
    ... et ...
    Code json : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    	"bdd/administration": {
    		"user": "toto",
    		"password": "123",
    		"host": "/tmp",
    		"port": 5432,
    	}
    	"joueur/parametrage": {
    		"bet": 10,
    		"miseMax": 100,
    	}
    }
    ... je sais vers lequel va ma préférence
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Oui tu as vu, j'ai corrigé mon erreur. Le Ramdisk diminue l'énergie consommée. Cela étant il faut que je te précise, que jadis j'ai travaillé à la maintenance électronique dans un casino. Et là, on ne rigole pas avec la sécurité. Pas de coupure de courant (des groupes sont présents) en cas de panne sur une machine, on prélève la carte électronique que l'on place sur une machine identique et on peut grâce à l' historique connaitre l'état du compteur "crédit" du joueur juste avant la panne . Même si c'est la carte qui est en panne, car elle aussi possède une sauvegarde permanente marchant avec une mémoire cMOS toujours alimentée et toujours lisible. Et si c'était elle qui est tombée en panne, diras-tu ? Alors toutes les machines en fonctionnement envoient à un serveur central leur historique en temps réel. Donc un joueur interrompu par une panne sera remboursé du cédit qu'il avait avant la panne augmenté de la mise maximale autorisée. Ces principes, je les ai respectés dans mon cahier des charges. (au pire, à une mise prêt).
    Voilà pour le ramdisk.

  17. #17
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ce n'est pas tout à fait notre objectif non plus. On cherche plutôt à concilier l'efficacité avec l'évolutivité (penser à ce que pourrait devenir le programme demain) avec la facilité de maintenance (quand la config est enregistrée dans un fichier texte, c'est plus facile de la vérifier, voire la réparer si elle a mal été enregistrée).


    Ils sont sympas, pas compliqués à comprendre, mais peut-être pas faits pour quelque chose d'aussi simple qu'une config. Ils peuvent gérer mais ça me donne l'impression d'utiliser une presse hydraulique pour presser une orange.
    Parce qu'entre...
    Code ini : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [bdd/administration]
    user=toto
    password=123
    host=/tmp
    port=5432
     
    [joueur/parametrage]
    bet=10
    miseMax=100
    ... et ...
    Code json : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    	"bdd/administration": {
    		"user": "toto",
    		"password": "123",
    		"host": "/tmp",
    		"port": 5432,
    	}
    	"joueur/parametrage": {
    		"bet": 10,
    		"miseMax": 100,
    	}
    }
    ... je sais vers lequel va ma préférence
    Tu m'as déjà émerveillé avec ton exemple au début du post quand j'ai vu comment tu as utilisé la bibliothèque "pickle" alors que moi, je m'étais arrêté au premier exemple qui m'a satisfait .... il se peut que JSON ne soit pas justifié dans mon cas.

  18. #18
    Expert confirmé Avatar de papajoker
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2013
    Messages
    2 321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nièvre (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2013
    Messages : 2 321
    Par défaut
    Citation Envoyé par azad2b Voir le message
    il est sauvé dans le répertoire ramdisk
    Ok, il y avait donc confusion, on avait compris que tu utilisais la ram du pc alors que tu désires une sauvegarde "temps réel" sur un périphérique externe (carte mémoire)
    C'est vrai que l'on attend des coupures de courant

    . il se peut que JSON ne soit pas justifié dans mon cas.
    Moi, je dis l'inverse, ici le but n'est pas d'éditer à la main ce fichier (même pas de la lire) donc un format presque "natif" dans python est plus simple (comme dit plus haut, lorsque tu fais un print de ta variable, tu as du json et certainement pas du "ini")
    https://docs.python.org/fr/3/library/json.html

    Version compliquée car nous avons plusieurs dictionnaires (pas ton cas ?)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    with open('stat.json', 'w') as json_file:
      json.dump([dicoStat, dicoApp], json_file)
      # json.dump(dicoStat, json_file)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    with open('stat.json', 'r') as json_file:
        dicoStat, dicoApp = json.load(json_file)
        # dicoStat = json.load(json_file)

  19. #19
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par azad2b Voir le message
    Tu m'as déjà émerveillé avec ton exemple au début du post quand j'ai vu comment tu as utilisé la bibliothèque "pickle"
    Non, là tu te trompes d'émerveillateur, celui dont tu parles c'était tyrtamos. Mais tu as raison, il émerveille beaucoup de monde. Moi j'adore quand il poste des exemples PyQt. A ce propos, tu devrais peut-être réfléchir à t'y mettre à la place de tk car ok c'est un peu galère au début mais ensuite on ne regrette pas.
    Quelques exemples/tutos... https://python.developpez.com/telech.../47/Hello-Word...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Membre confirmé
    Inscrit en
    Février 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Février 2007
    Messages : 64
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Non, là tu te trompes d'émerveillateur, celui dont tu parles c'était tyrtamos. Mais tu as raison, il émerveille beaucoup de monde. Moi j'adore quand il poste des exemples PyQt. A ce propos, tu devrais peut-être réfléchir à t'y mettre à la place de tk car ok c'est un peu galère au début mais ensuite on ne regrette pas.
    Quelques exemples/tutos... https://python.developpez.com/telech.../47/Hello-Word...
    Je reconnais que PyQt m'a tenté, quelquefois. Mais là encore, je me heurte à ce qui me déplait le plus dans ce Python, qui pourtant permet de créer des applications moderne très (trop, même, hélas) facilement : la profusion de bibliothèques !
    Mais tu as raison. Puisque je me suis enfin décidé au grand ménage, je vais réétudier la question. Tkinter est certes un peu vieillot mais mon application n'utilise pas de boutons, ni la souris, ni les menus. La simulation d'un VidéoPoker célèbre en 1980 n'a pas besoin de tels outils. Mais si, accessoirement, PyQt permet de simplifier l'organisation du projet, alors, oui, je m'y met. Merci encore.

Discussions similaires

  1. Réponses: 2
    Dernier message: 19/10/2021, 12h14
  2. Réponses: 2
    Dernier message: 27/11/2015, 10h22
  3. [Python 2.X] [PYTHON - ArcPY] Copier-coller classe d'entité vers classe d'entité globale
    Par Falmar dans le forum Général Python
    Réponses: 0
    Dernier message: 27/10/2015, 14h16
  4. Global Hot Key avec python 3.xx..
    Par gaut5 dans le forum Général Python
    Réponses: 6
    Dernier message: 21/08/2014, 21h45
  5. les variables globales static
    Par gRRosminet dans le forum C
    Réponses: 8
    Dernier message: 27/04/2002, 08h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo