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 :

Meilleur façon de répéter N fois un appel


Sujet :

Python

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 114
    Par défaut Meilleur façon de répéter N fois un appel
    Bonjour


    Selon vous, quelle est la meilleur manière de répéter N fois un appel de fonction.

    Mes premières tentatives étaient directement inspirées de ce qui se fait en C :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    i=0
    while i<10:
        ma_fonction()
        i = i +1
    Depuis j'ai un peu changé pour
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for i in range(10):
       ma_fonction()
    Est-ce qu'il existe une manière encore plus propre ?

    Cordialement
    Emmanuel

  2. #2
    Membre expérimenté Avatar de alexdevl
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    265
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 265
    Par défaut
    Bonjour,
    Il est possible d'utiliser des list-comprehension pour avoir la boucle en une ligne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    def ma_fonction(x):
        print x
        return "ok"
     
    # Lancement direct
    [ma_fonction(i) for i in range(10)]
     
    # ou pour avoir un retour dans une liste :
    infoRetour=[ma_fonction(i) for i in range(10)]
    print infoRetour

  3. #3
    Expert confirmé
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Par défaut
    Si c'est pour éxécuter toujours la même fonction, i étant une variable muette (donc inutile), tu peux aussi passer par itertools.repeat (c'est pas dit que ce soit plus rapide)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import itertools()
    for i in itertools.repeat(ma_fonction, 10):
        i()

  4. #4
    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,

    Pour mémoire, il y a aussi les expressions génératrices.

    La syntaxe est la même que les compréhensions de listes, à part que l'on utilise les parenthèses au lieu des crochets. Mais cela fabrique un itérateur au lieu d'une liste. 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
     
    cube = (i*i*i for i in xrange(0,10))
    for x in cube:
        print x
     
    0
    1
    8
    27
    64
    125
    216
    343
    512
    729
    Par rapport à la compréhension de liste, l'avantage est qu'on peut utiliser chaque élément de la liste sans avoir à la fabriquer (donc, consommation plus faible de mémoire). Pour la rapidité, je ne sais pas.

    Tyrtamos

  5. #5
    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
    On peut aussi fabriquer un itérateur à partir d'une classe:

    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
     
    class Cube(object):
     
        def __init__(self, deb, fin):
            self.cpt = deb  # initialisation du compteur
            self.fin = fin
     
        def __iter__(self):
            return self
     
        def next(self):
            if self.cpt>=self.fin:
                raise StopIteration
            k = self.cpt
            self.cpt += 1  # incrementation du compteur
            return k*k*k 
     
    for i in Cube(0,10):
        print i
     
    0
    1
    8
    27
    64
    125
    216
    343
    512
    729
    L'avantage étant le même que précédemment: on peut exploiter chacun des éléments de la séquence sans avoir à créer la liste complète en mémoire. C'est comme xrange(), à part qu'ici, on peut renvoyer des éléments plus complexes (ici, le cube du compteur).

    On pourrait aussi passer une fonction comme paramètre. Par 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
     
    def cube(x):
        return x*x*x
     
    class xplage(object):
     
        def __init__(self, fn, deb, fin, pas=1):
            self.fn = fn
            self.cpt = deb  # initialisation du compteur
            self.fin = fin
            self.pas = pas
     
        def __iter__(self):
            return self
     
        def next(self):
            if self.cpt>=self.fin:
                raise StopIteration
            k = self.cpt
            self.cpt += self.pas  # incrementation du compteur
            return self.fn(k) 
     
    for i in xplage(cube,0,10):
        print i
    Tyrtamos

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 114
    Par défaut
    Tout d'abord merci pour toutes ces réponses.

    Je rappel que je cherche seulement une manière élégante de répéter N appels à une fonction.

    On va dire que la fonction à appeler est celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    def MaFunction():
        print "Je suis là"
    Pour l'instant deux solutions retiennent mon attention :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for i in range(10):
       MaFonction()
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    [MaFonction() for i in range(10)]
    Ces deux solutions sont courtes, et en générale plus c'est court mieux c'est.
    Cependant dans les deux cas, j'ai besoin d'une variable i qui ne sert à rien, mise à part compter les itérations.

    Pour moi, la première méthode a l'avantage d'être plus compréhensible surtout par ceux qui maitrise mal le python. La deuxième méthode à l'avantage d'être très court, et de permettre de récupérer la valeur de chaque appel.

    Existe-t-il un aspect du python que je ne connais pas encore qui permette d'appeler N fois une fonction sans créer de variable que quelqu'un avait qualifiée de muette

    Cordialement
    Emmanuel

  7. #7
    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
    Il y a aussi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    def mafonction(i):
        print "coucou"
     
    map(mafonction, xrange(0,5))
     
    coucou
    coucou
    coucou
    coucou
    coucou
    La fonction map exécute la fonction "mafonction" avec pour argument chacun des éléments de la séquence qui suit.

    Mais je ne sais pas si map continuera d'exister dans les versions suivantes de Python (j'utilise encore la 2.5).

    Tyrtamos

    Edit: mais si map n'existait plus, il est facile à refabriquer:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    xmap = lambda fn, seq: [fn(x) for x in seq]

  8. #8
    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
    Comme tout le monde s'y met à coeur joie...

    Je propose ceci, qui est une variante de la solution de Guigui:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for f in [ma_fonction]*10:
        f()
     
    ou bien:
     
    for f in (ma_fonction,)*10:
        f()

  9. #9
    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
    Et en voici une autre, plutôt inhabituelle mais très courte:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    eval('mafonction(),'*10)
    Si nécessaire, on pourrait transmettre les bibliothèques de variables globales et locales si mafonction() en utilise.

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut le Python est-il pêcheur ?
    Est-ce qu'il existe une manière encore plus propre ?
    Qu'est ce que ça veut dire «plus propre» ?

    je cherche seulement une manière élégante de répéter N appels à une fonction
    Qu'est ce que ça veut dire «manière élégante» ?

    Ce doit être quand «c'est court». Parce que
    en général plus c'est court mieux c'est.
    Mais qu'est ce que ça veut dire «mieux c'est» ?

    ---------------------

    Cependant dans les deux cas, j'ai besoin d'une variable i qui ne sert à rien, mise à part compter les itérations.
    Ça me fait imaginer la scène suivante: un pêcheur du néolithique (avant l'invention de l'écriture, ce qui exclut une représentation mentale de nombres encore jamais écrits) qui rouspète sur une grève: «Ah lala, que je pêche avec un harpon ou avec un filet, j'ai besoin d'une main qui ne sert à rien, mis à part compter les poissons que je dois obtenir pour mes 3 enfants et ma femme».

    C'est un peu tiré par les cheveux, mais c'est pour dire que compter c'est toujours établir une correspondance entre une succession de choses et un ensemble stable d'éléments pris comme référence de comptage, que ce soit les doigts de la main, des petits cailloux assemblés en tas de diverses manières, des noeuds sur des cordelettes, des signes écrits arbitraires ou la représentation mentale de ces signes.
    Et que cette représentation va se traduire dans un programme informatique par l'utilisation d'un ensemble ou d'une variable, comment faire autrement ?

    Dans tous les exemples ci-dessus, qu'on le perçoive immédiatement ou non, il y a toujours un ensemble ou une variable qui servent à surveiller le déroulement de l'itération, non ?
    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for f in (ma_fonction,)*10:
        f()
    si on fait print (ma_fonction,)*10
    on voit qu'il s'agit d'un tuple de 10 objets-fonction. Je suis pas sûr que ce soit mieux que d'itérer i dans range(10).
    Je ne connait pas bien eval() mais je subodore que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    eval('mafonction(),'*10)
    nous fait un truc du même genre.
    Dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [MaFonction() for i in range(10)]
    aussi il y a un ensemble: range(1) est [0,1,2,3,4,5,6,7,8,9]

    ---
    Par contre, dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for i in itertools.repeat(ma_fonction, 10):
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cube = (i*i*i for i in xrange(0,10))
    ça me semble déjà mieux: il n'y a pas d'ensemble construit en préalable. Il y a un indice i qui prend des valeurs successivement calculées (cf définition de repeat(), l'équivalent contient xrange() ).
    Mais ces valeurs appartiennent bien à l'ensemble conceptuel des nombres de 1 à 10. D'une manière ou d'une autre si on veut compter, il y a bien des doigts ou une variable qui intervient quelque part, muette ou pas.

    «ça me semble déjà mieux» , ça veut dire quoi ?
    Ça veut dire que ça tient moins de place en mémoire.

    Un autre critère pour savoir ce qui serait "mieux" serait la vitesse d'exécution de chaque solution proposée.

    Bref,
    astuce algorithmique, je veux bien, mais élégance d'un code, fondée sur son apparence, je ne vois pas trop ce que ça veut dire.

    NB: tout ceci, dit sans acrimonie. Je me pose en fait souvent ce même genre de question un peu stérile


    EDIT
    au fait, voici une solution dans laquelle il n'y a pas de variable muette et pas de nombre 10. Mais c'est illusoire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def f(x):
        print 'Je suis la'
        return x[:-1]
     
    x = 'abcdefghij'
    while x:  x = f(x)

  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
    A part l'utilisation mémoire et la vitesse d'exécution, il y a un autre élément qui peut avoir son importance, mais il est plus subjectif: l'élégance du code. Pour moi, elle est liée à la lisibilité du code, c'est à dire la facilité avec laquelle un lecteur va comprendre ce que fait un morceau de code. C'est particulièrement important en Python, car c'est un langage assez riche pour exprimer simplement beaucoup de choses. Ce n'est pas pour rien qu'on dit que le code Python ressemble à du pseudo-code.

    Avec ce critère, je trouve ton dernier morceau de code, eyquem, très mauvais car très obscur (tu en conviendras certainement; j'ai bien compris que ce n'était pas une proposition sérieuse).

    Le code avec la compréhension de liste (ou encore mieux: une generator expression, le cas échéant) est pour moi ce qu'il y a de mieux si on veut effectivement garder le résultat des appels. Mais si on n'exécute la fonction plusieurs fois que pour ses effets de bord, il n'est pas idéal car cet aspect n'est pas immédiatement apparent. Dans ce cas, la solution que je trouve la plus élégante est celle de Guigui avec repeat; sa lecture est proche de l'énoncé du problème en français. Son seul défaut est de faire appel à une fonction que tout le monde ne connais pas. Si le but est d'être compris le plus facilement par le plus grand nombre (tout en restant efficace), la solution avec la boucle for classique et le (x)range(10) est peut-être bien le meilleur choix.

    Mais je dois admettre que Ruby permet de faire mieux que Python dans ce cas-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    10.times { ma_fonction }
    D'un simplicité sidérante, n'est-ce pas ?

  12. #12
    Membre Expert
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Par défaut
    Allez je mets la mienne aussi !!

    Le for étant une structure des plus courantes, je reste sur li='dée que dans ce cas là c'est la plus "lisible".

    Concernant la demande du départ, 2 points que je retiens, utilisé xrange qui est plus économique en mémoire. Range construit une liste qui est itéré, alors que xrange est l'équivalent d'un yield sans construction de liste intermédiaire.

    D'autre part, pour ne pas noté 'i' qui ne sert à rien, on peut utiliser '_' qui représente une variable qui justement indique qu'elle ne sert à rien.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    def func():
        pass
     
    for _ in xrange(10):
        func()
    Concernant range et xrange :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    x = range(10)
    print x, type(x)
     
    x = xrange(10)
    print x, type(x)
    renvoi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] <type 'list'>
    xrange(10) <type 'xrange'>

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

Discussions similaires

  1. Appel connexion SQL, meilleure façon de procéder ?
    Par Lekno dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 8
    Dernier message: 07/06/2014, 16h49
  2. La meilleure façon d'appeler une page
    Par The eye dans le forum VB.NET
    Réponses: 1
    Dernier message: 26/01/2008, 13h10
  3. Liste d'objets, quel est la meilleure façon
    Par shirya dans le forum C++
    Réponses: 2
    Dernier message: 08/12/2005, 17h59
  4. [XSLT][XML] Répéter n fois la construction d'un bout XML
    Par enimren dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 11/11/2005, 18h42
  5. Est ce bien la meilleure façon de faire un histogramme ?
    Par rvzip64 dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 10/05/2005, 13h41

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