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 :

Comment créer une liste ou une instance de classe dans une fonction ?


Sujet :

Python

  1. #1
    Membre régulier Avatar de Neolander
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 88
    Points : 87
    Points
    87
    Par défaut Comment créer une liste ou une instance de classe dans une fonction ?
    Bonjour !

    Face au constat déprimant que le pascal est à peu près mort aujourd'hui, je me suis mis au python via le livre de Gérard Swinnen. Globalement, c'est assez sympathique comme langage si l'on oublie quelques petites contraintes énervantes comme on en trouve dans tous les langages (le fait de devoir mettre self partout... ça fait du code tellement lourd à lire... ).

    Mais il y a une limitation du langage qui est vraiment énorme, ce qui me laisse penser qu'elle n'en est pas une et que c'est moi qui n'ai rien compris, c'est l'impossibilité de créer une instance de classe ou une liste dans une fonction.

    Je m'explique par un exemple concret (note : oui, je sais, y'a des fautes de codage par floppée dans le code qui suis, je l'ai un peu corrigé après heureusement ^^).

    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
    def charger_obstacles(obstacles, nom_fichier):
      "Charge une liste d'obstacles (qui doit être précédemment initialisée)"
      resultat = ""
      try:
        f = open(nom_fichier, "r")
        #Vérification du type de fichier et de la version des obstacles utilisée
        s = f.readline()
        if s!="***Données d'Obst@cleS***":
          f.close()
          return "erreur:type"
        s = f.readline()
        if s!="Version : "+version_obst:
          resultat = "danger:version"
        #Lecture du nombre d'obstacles dans le fichier
        nb = int(f.readline()[9:])
        #Chargement proprement dit...
        obstacles = []
        for i in range(nb):
          obstacles.append(Obstacle())
          obstacles[i].charger(fichier)
        #...et comme on est poli on oublie pas de fermer la porte en sortant.
        f.close()
      except:
        resultat = "erreur:fichier"
      return resultat
    Ce code est censé remplir la liste "obstacles" avec des éléments piochés dans un fichier. Dans la pratique, il le fait très bien, mais seulement à l'intérieur de la fonction, car bien évidemment, l'infâme python, quand on quitte la fonction, décrète que son espace de noms est inutile et bon à jeter.

    En pascal le problème ne se serait pas posé, un petit var et on n'en parle plus...
    En C++ on aurait mis un & devant et cf pascal...
    Mais en python, y-a-t'il un moyen propre (non, pitié, pas la variable globale !) pour que ma liste survive à ça ?

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 478
    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 478
    Points : 9 280
    Points
    9 280
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je partage ton avis concernant le langage pascal.

    Sinon, l'argument d'une fonction, si c'est une liste, est passé par adresse, et les modifications au sein de la fonction sont récupérables à l'extérieur comme avec le "var" du pascal. Dans ton exemple, c'est le cas de la variable liste "obstacles".

    Petit code qui montre cela (ça affiche 'toto'):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def test(L):
        L.append('toto')
    L=[]
    test(L)
    print L
    Si la variable globale t'embête, ça marche aussi de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    def test(L):
        L.append('toto')
    def machin():
        L=[]
        test(L)
        print L
    machin()
    Cependant, cette possibilité dépend du type de l'argument. Par exemple, avec une variable chaîne, ça ne marche plus. L'exemple suivant n'affiche rien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def test(ch):
        ch='toto'
    ch=''
    test(ch)
    print ch
    Tyrtamos

  3. #3
    Membre régulier Avatar de Neolander
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 88
    Points : 87
    Points
    87
    Par défaut
    Merci de cette réponse bien détaillée !

    Maintenant ça a l'air de marcher... Je vais donc pouvoir poursuivre la création de mon jeu de sadique avec son moteur physique qui dépote

    (La variable globale, c'est parce qu'à un moment, désespéré, j'avais envie de faire un équivalent python du "new" et "delete" du C++ à base de variable globale )

  4. #4
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Pourquoi n'utilises-tu pas la valeur de retour pour retourner a liste?

    Thierry

  5. #5
    Membre régulier Avatar de Neolander
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 88
    Points : 87
    Points
    87
    Par défaut
    Parce que je l'utilise déjà pour retourner des informations (si ça a planté, réussi, et pourquoi...). Ca m'a semblé plus logique que l'inverse.

    Ma procédure retourne "" si ça a marché, "erreur:fichier" si une erreur s'est produite pendant la lecture (un jour, je coderai peut-être un truc plus précis qui dira ce qui s'est passé exactement...), "erreur:type" si on lui a mis n'importe quoi comme fichier, et "danger:version" si on lui a mis un fichier provenant d'une mauvaise version du programme (ça c'est pour plus tard...), tout en essayant de charger le fichier tout de même

    Une version à jour de la procédure, au passage...
    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 charger_obstacles(obstacles, nom_fichier):
      "Charge une liste d'obstacles (qui doit être précédemment initialisée)"
      resultat = ""
      try:
        f = open(nom_fichier, "r")
        #Vérification du type de fichier et de la version des obstacles utilisée
        s = f.readline()
        if s!="***Données d'Obst@cleS***\n":
          f.close()
          return "erreur:type"
        s = f.readline()
        if s!="Version : "+version_obst+"\n":
          resultat = "danger:version"
        #Lecture du nombre d'obstacles dans le fichier
        nb = int(f.readline()[9:])
        #Chargement proprement dit...
        for i in range(nb):
          obstacles.append(Obstacle())
          obstacles[i].charger(f)
        #...et comme on est poli on oublie pas de fermer la porte en sortant.
        f.close()
      except:
        resultat = "erreur:fichier"
      return resultat

  6. #6
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Citation Envoyé par Neolander Voir le message
    Parce que je l'utilise déjà pour retourner des informations (si ça a planté, réussi, et pourquoi...). Ca m'a semblé plus logique que l'inverse.
    Pour la gestion des erreurs, je préfère personnellement lever une exception. Mais si tu tiens à renvoyer les messages d'erreur, rien ne t'empêche de faire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def maFonction():
        liste = []
        liste.extend([1,2,3,4,5])
        return liste, "Message d'erreur"
     
    if __name__ == "__main__":
        maListe, erreur = maFonction()
        print maListe
        print erreur
    Dans ce cas, la fonction retourne un tuple de valeurs.

    Thierry

  7. #7
    Membre régulier Avatar de Neolander
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 88
    Points : 87
    Points
    87
    Par défaut
    Les exceptions... En pascal j'y touchais pas trop (juste le minimum vital : try + except pour me créer des messages d'erreurs personnalisés quand y'a un EDivideByZero ^^) alors logiquement en python j'en sais pas plus...

    Mais je suis ouvert à toute explication, ça semble plus élégant comme solution que les tuples ou celle que j'avais prise !

  8. #8
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Citation Envoyé par Neolander Voir le message
    Les exceptions... En pascal j'y touchais pas trop (juste le minimum vital : try + except pour me créer des messages d'erreurs personnalisés quand y'a un EDivideByZero ^^) alors logiquement en python j'en sais pas plus...

    Mais je suis ouvert à toute explication, ça semble plus élégant comme solution que les tuples ou celle que j'avais prise !
    Voici un exemple assez artificiel où je lève une exception de type MaFonctionErreur avec le message "Erreur type de fichier" en cas de type de fichier erroné et une exception du même type avec le message "Impossible d'ouvrir le fichier" en cas de problème pendant l'ouverture:

    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
    from __future__ import with_statement
     
    class MaFonctionErreur(Exception):
        pass
     
    def maFonction():
        liste = [1,2,3,4,5]
        try:
            with open("test2.txt", "r") as f:
                s = [line[:-1] for line in f]
                if s[0] != "***Données d'Obst@cleS***":
                    raise MaFonctionErreur("Erreur type de fichier")
        except IOError:
            raise MaFonctionErreur("Impossible d'ouvrir le fichier")
     
        return liste
     
    if __name__ == "__main__":
        try:
            maListe = maFonction()
            print maListe
        except MaFonctionErreur, e:
            print e
    Thierry

  9. #9
    Membre régulier Avatar de Neolander
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    88
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 88
    Points : 87
    Points
    87
    Par défaut
    Petite question technique : est-ce que raise, comme return, provoque l'arrêt d'une fonction si il est lancé en plein milieu ?

    En tous cas, c'est vrai que c'est nettement plus pratique comme ça, merci !

  10. #10
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Citation Envoyé par Neolander Voir le message
    Petite question technique : est-ce que raise, comme return, provoque l'arrêt d'une fonction si il est lancé en plein milieu ?
    Oui

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

Discussions similaires

  1. Réponses: 8
    Dernier message: 22/04/2011, 21h27
  2. [AC-2010] Comment afficher une autre valeur que la clé primaire dans une liste déroulante
    Par Nephi dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 17/09/2010, 17h04
  3. Remplir une liste déroulante à partir d'un champ dans une pop up
    Par wiam26 dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 23/08/2006, 16h42
  4. Réponses: 4
    Dernier message: 24/11/2005, 09h11

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