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 :

Premier programme en python


Sujet :

Python

  1. #1
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut Premier programme en python
    Bonjour,

    Je me suis mis très récemment à apprendre python.
    Après avoir fait plusieurs "hello world", j'ai entrepris de re-coder mon petit script shell qui permet de changer mon fond d'écran qui n'est pas très bien adapté (car la séquence des images est toujours la même et non aléatoire).

    Le but étant de lister les images d'un répertoires, les stocker dans un tableau associatif contenant le chemin vers l'image, un numéro d'image qui commence à 0 et un status (true/false). Le status me permet de savoir que l'image a déjà été utilisée et donc une autre image est choisie. Le script étant lancé par crontab, je stock le tableau dans un fichier xml qui est repris au prochain lancement du job.

    J'ai réussi à faire tout ça (non sans mal, mais j'ai mis environ une semaine pour comprendre, chercher les infos, la syntaxe etc).

    Mon problème vient du fait que si le script a passé toute les images (donc elles ont toutes le status true), il faut que je relance une nouvelle liste pour remettre tous les status à false et donc prendre en compte les nouvelles images ajoutées au dossier. Et là, je sèche.

    voilà la fonction qui gère les status:
    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
    ...
    ...
    # return a random background
    def get_item(files):
    	item = random.randrange(len(files))
    	for fic, status in files[item].iteritems():
    		if status == "false":
                        files[item] = {fic: "true"}
     
                        root_element = ET.Element("my_list")
                        for i in files:
                            for j,k in files[i].iteritems():
                                child = ET.Element("img")
                                child.attrib["id"] = str(i)
                                child.attrib["file"] = j
                                child.attrib["status"] = k
                                root_element.append(child)
                                #print i,j,k
     
                        tree = ET.ElementTree(root_element)
                        tree.write(tmp_path + "/" + list_file)
     
                        return fic
    		else:
                        return 0
    ...
    ...
    # main program #
     
    # populate the list
    files = get_list_from_file(img_path)
     
    # get a random file
    item = 0
    while item == 0:
        item = get_item(files)
     
    # set background
    print item
    #set_wallpaper(item)
    ...
    ...
    En fait il faudrai que je vérifie dans le tableau de la fonction get_item si tous les status sont à true avant de pouvoir relancer une nouvelle liste. Existe t il une super fonction qui me permette de faire ça ?

    J'espère m'être bien exprimé.

    Merci d'avance pour votre aide

  2. #2
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Bon, pour répondre à ta question précise, tu pourrais utiliser la fonction builtin filter(), qui applique à chaque élément d’un iterable une fonction, et retourne une liste contenant les éléments pour lesquels la dite fonction a retourné True. Ça pourrait donner quelque chose comme ça (je ne comprends pas très bien ta structure de donnée files, donc il faudra probablement adapater…)*:

    Code python : 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
    # return a random background
    def get_item(files):
            # En supposant que les élément de files sont des dicts avec un membre "status" à chaque fois.
            tfiles = filter(lambda f: f["status"], files)
            # Maintenant, tfiles ne contient que les éléments non-encore utilisés...
    	item = random.randrange(len(tfiles))
    	for fic, status in tfiles[item].iteritems():
    		if status == "false":
                        tfiles[item] = {fic: "true"}
     
                        root_element = ET.Element("my_list")
                        for i in tfiles:
                            for j,k in tfiles[i].iteritems():
                                child = ET.Element("img")
                                child.attrib["id"] = str(i)
                                child.attrib["file"] = j
                                child.attrib["status"] = k
                                root_element.append(child)
                                #print i,j,k
     
                        tree = ET.ElementTree(root_element)
                        tree.write(tmp_path + "/" + list_file)
     
                        return fic
    		else:
                        return 0

    Encore une fois, ce code ne va pas marcher tel quel, je ne comprends pas assez ta structure de donnée files…

    Maintenant, quelques remarques d’ordre plus général, qui devraient énormément te simplifier la vie*:

    * Pourquoi utiliser XML*? Ça rajoute beaucoup de code pour le gérer, alors que le module (c)pickle te permet d’enregistrer la plupart des structures de donnée python dans un format compact et rapide à (dé)sérialiser.

    * Je pense qu’une structure à deux listes serait bien plus facile à gérer, que l’utilisation d’un boolean status*:
    ** Tu remplis une liste avec tous les éléments (tous tes chemins de fichier)., et en crées une deuxième, vide pour le moment.
    ** À chaque itération, tu chosis un élément au hasard dans cette liste, fais ce que tu veux avec, puis le supprimes de la première liste et l’ajoute à la seconde.
    ** Lorsque la première liste est vide, tu lui assignes la deuxième (qui est maintenant pleine), et assignes ensuite à la deuxième une nouvelle liste vide…

    Bon courage*!

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    dans l'idée j'aurai vu ça autrement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    images = liste des images
    index = choice(range(len(images)-1)) # choisit une image au hasard dans l'interval [0:-1]
    img = images.pop(index) # retire l'image du tas
    img ==> wallpaper
    images.append(img) # remet l'image à la fin du tas
    pour se donner une idée du truc ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from random import choice
    images = ['a','d','v','x']
    while True:
        index = choice(range(len(images)-1)) # au cas ou on ajoute/retire des images
        img = images.pop(index)
        print 'image affichee: ',img
        images.append(img)
        raw_input('suivante ...')

  4. #4
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Bonjour, voici comment je rempli mon tableau. img_path est le chemin vers le dossier images, et je crée une structure de données avec comme index i et comme donnée le nom de l'image: status

    Il n'y a pas de membre nommé "status"

    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
    def get_list_from_fs(img_path):
    	i = 0
    	global pile
     
    	root_element = ET.Element("my_list")
     
    	for dirname, dirnames, filenames in os.walk(img_path):
    		for filename in filenames:
    			fic = os.path.join(dirname, filename)
    			pile[i] = {fic: 'false'}
    			child = ET.Element("img")
    			child.attrib["id"] = str(i)
                            child.attrib["file"] = fic
                            child.attrib["status"] = "false"
    			root_element.append(child)
    			i = i+1
     
    	# print ET.tostring(root_element)
            tree = ET.ElementTree(root_element)
            tree.write(tmp_path + "/" + list_file)
    	return pile
    Par contre l'idée d'utiliser une liste plutôt qu'un tableau associatif est intéressant. Le souci, c'est que le choix aléatoire de l'index peut très bien reprendre une image déjà utilisée dans la liste en cours. D'où le tableau avec le status pour pouvoir recharger la même liste à la prochaine exécution du cron.

    Je vais tout de même aller voir la doc des listes et de filter.

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    Citation Envoyé par zerros Voir le message
    Par contre l'idée d'utiliser une liste plutôt qu'un tableau associatif est intéressant. Le souci, c'est que le choix aléatoire de l'index peut très bien reprendre une image déjà utilisée dans la liste en cours. D'où le tableau avec le status pour pouvoir recharger la même liste à la prochaine exécution du cron.

    Je vais tout de même aller voir la doc des listes et de filter.
    tu as vu mon code ?

    dans ton code, qu'est-ce qui garantit que l'image qui finit un cycle ne commence pas le suivant ?

  6. #6
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Oui, ton code est très intéressant. je suis en train de faire des tests sur les listes.

    En fait, à la fin du cycle, peu importe que l'image qui finit puisse être la première qui commence (ce qui ne risque pas vraiment d'arriver pour des répertoires avec des centaines de photos). Le but est de re-générer la liste à partir du répertoire et donc de relancer un nouveau cycle.

  7. #7
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Ben dans ce cas, c’est très simple*: tu enlèves à chaque fois un élément (une image) de la liste, au hasard, et quand ta liste est vide, tu la reconstruis depuis le contenu du dossier*!

    Et encore une fois, je te conseille vraiment pickle à la place de XML pour la persistance de tes données (de ta liste), c’est beaucoup plus simple à gérer en python*!

  8. #8
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    sinon, pourquoi utiliser cron ?
    lances ton script au démarrage: une boucle infinie + une temporisation ça devrait le faire.

  9. #9
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Non, je voudrai pouvoir exécuter depuis la cron pour que chacun puisse gérer sa propre fréquence sans mettre la main dans le code.

    Et puis, ce script est juste une alternative à mon vieux script shell. c'est vraiment pour apprendre python. Alors peut-être que lorsqu'il fonctionnera vaec la cron, je ferai la version daemon :p

    Bonne idée pour la liste je teste ça de suite

  10. #10
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Bon, euh, j'ai pas mal de choses sur le feu, alors je vais tester ça tantôt,
    et je reviens vous dire que c'est bon :p

    ça va m'obliger à revoir ma copie sur la partie xml :s Un simple fichier texte devrait faire l'affaire si j'utilise les listes plutôt que les tableaux.

    ouf, ça m'enlève une surcharge lol. Mais au moins, je sais utiliser le xml avec python na na na :p

    ça avance, ça avance ... à tout à l'heure

  11. #11
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Citation Envoyé par josmiley Voir le message
    sinon, pourquoi utiliser cron ?
    lances ton script au démarrage: une boucle infinie + une temporisation ça devrait le faire.
    Mon point de vue est exactement l'inverse: pourquoi utiliser un daemon lorsqu'on peut utiliser cron ? Un daemon monopolise de la mémoire (même si c'est surtout de la mémoire virtuelle) et est plus délicat à écrire (il faut bien faire attention à libérer toutes les ressources qu'on utilise).

    Zerros, en Python on appelle "dictionnaire" ce que tu appelles "tableau". En effet, dans ton cas une simple liste suffit, mais pour info, une solution plus simple qu'XML et même plus simple que pickle pour avoir un dictionnaire persistant est d'utiliser le module shelve.

  12. #12
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    euh, merci pour les précisions. Pour le moment j'écris dans un fichier texte. j'ai viré tte la partie xml, et je suis passé en liste avec .pop qui vide la liste au fur et à mesure (merci josmiley).

    Je suis confronté à un problème quand la liste est vide:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Traceback (most recent call last):
      File "/home/azer/NetBeansProjects/ChangeBackgd/src/changebackgd.py", line 87, in <module>
        item = get_item()
      File "/home/azer/NetBeansProjects/ChangeBackgd/src/changebackgd.py", line 55, in get_item
        index = random.randrange(len(pile)-1)
      File "/usr/lib/python2.7/random.py", line 192, in randrange
        raise ValueError, "empty range for randrange()"
    ValueError: empty range for randrange()
    Voilà mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def get_item():
    	index = random.randrange(len(pile)-1)       
            fic = pile.pop(index)
     
            handle = open(tmp_path + "/" + list_file, 'w')
            for i in pile:
                handle.write(pile[i] + "\n")
     
            handle.close()
            return fic
    Comment puis-je vérifier si la variable index est vide (empty) ? il doit certainement exister une fonction python empty non ?

  13. #13
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Citation Envoyé par dividee Voir le message
    Mon point de vue est exactement l'inverse: pourquoi utiliser un daemon lorsqu'on peut utiliser cron ? Un daemon monopolise de la mémoire (même si c'est surtout de la mémoire virtuelle) et est plus délicat à écrire (il faut bien faire attention à libérer toutes les ressources qu'on utilise).

    Zerros, en Python on appelle "dictionnaire" ce que tu appelles "tableau". En effet, dans ton cas une simple liste suffit, mais pour info, une solution plus simple qu'XML et même plus simple que pickle pour avoir un dictionnaire persistant est d'utiliser le module shelve.
    En fait, je suis aussi de ton point de vue, mais puisque je suis débutant, ça m'intéressera aussi d'apprendre à coder un démon en python je vais aussi aller regarder ce qu'est shelve et pickle

  14. #14
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Bon c'est tout bon.

    J'ai utilisé try except pour gérer cette exception et relancer la création d'une nouvelle liste.

    Merci à tous. Je passe le topic en résolu et je reviendrai certainement pour poser des questions pour la version daemon.

  15. #15
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    Citation Envoyé par zerros Voir le message
    1-ce qui ne risque pas vraiment d'arriver pour des répertoires avec des centaines de photos
    ...
    2-J'ai utilisé try except pour gérer cette exception et relancer la création d'une nouvelle liste.
    1- voir loi de Murphy.
    2- le code que je t'ai proposé remplit la liste en même temps qu'il la vide.
    bon après, si ça fonctionne quelque soit le moyen ... "There's more than one way to do it"

  16. #16
    Membre éclairé
    Profil pro
    Expert technique
    Inscrit en
    Septembre 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert technique

    Informations forums :
    Inscription : Septembre 2003
    Messages : 328
    Par défaut
    Oui, et je l'ai utilisé. Merci

    Mais lorsque la liste est vide, random génère une exception puisqu'il essaie de prendre un index qui n'existe pas.

    j'ai donc fait:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def get_item():
            try:
                index = random.randrange(len(pile))
                fic = pile.pop(index)
     
                handle = open(tmp_path + "/" + list_file, 'w')
                for i in pile:
                    handle.write(pile[i] + "\n")
     
                handle.close()
                return fic
     
            except ValueError:
                return "empty"
    Et dans mon main:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    if item == "empty":
        # remove list when it's empty
        if os.path.isfile(tmp_path + "/" + list_file):
            os.remove(tmp_path + "/" + list_file)
     
        # populate the list
        pile = get_list_from_file(img_path)
        # get a random item
        item = get_item()
        # set background
        set_wallpaper(item)
    else:
        # set background
        set_wallpaper(item)
    impeccable Je génère un .pyc et je teste la portabilité du script

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/10/2014, 19h01
  2. problème premier programme avec python
    Par adolphemartins dans le forum Général Python
    Réponses: 3
    Dernier message: 04/12/2011, 12h45
  3. Premier programme en Python
    Par VinsS dans le forum Contribuez
    Réponses: 2
    Dernier message: 17/11/2008, 14h36
  4. Premier programme sous Python
    Par Helios07 dans le forum Général Python
    Réponses: 6
    Dernier message: 06/06/2008, 10h33

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