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 :

Récupérer les noms non définis dans une chaine pour effectuer la fonctions 'eval'


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 36
    Points : 24
    Points
    24
    Par défaut Récupérer les noms non définis dans une chaine pour effectuer la fonctions 'eval'
    Bonjour,

    Le titre est un peu obscure comme ça, alors je m'explique.

    L'utilisateur doit entrer une chaine de caractères à évaluer (fonction mathématique), par exemple :
    x^2/abs(a)

    Si j'évalue cette chaine (avec eval) j'obtiens naturellement une erreur, car 'x' et 'a' ne sont pas des noms définis.

    J'aimerais pouvoir récupérer une liste des noms non-définis dans cette chaine (sous forme d'une liste par exemple), afin de pouvoir les définir moi-même (en faisant un dict : {'x':1.2, 'a':0.3} par exemple), pour pouvoir faire un eval ensuite...

    J'entrevoie bien une méthode en exploitant le message d'erreur "name 'a' is not defined", mais ça me parrait pas très "élégant"

    J'espère avoir été suffisamment clair...

    Merci d'avance

  2. #2
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    hummm, comme ca je pense qu'il serait mieux de faire un declaration de variable via une chaine de carratere
    voir ici :http://python.developpez.com/faq/?pa...es#GenStrDecla

    si tu es sur que a et x existent dans ton dictionnaire de variable, tu crée une variable a partir de ton expression.

    c'est une piste a explorer... peut etre que ca marchera!

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 36
    Points : 24
    Points
    24
    Par défaut
    hummm, comme ca je pense qu'il serait mieux de faire un declaration de variable via une chaine de carratere
    D'accord, mais je voudrais savoir comment elles s'appellent ces variables.

    si tu es sur que a et x existent dans ton dictionnaire de variable, tu crée une variable a partir de ton expression
    Je ne suis sur de rien ...

    Je résume ce qui doit se produire :

    1) L'utilisateur tape l'expression : v1^3+45/xyz
    2) Moi (enfin, mon logiciel) "identifie" deux noms non-définis : v1 et xyz
    3) Connaissant ces noms, je crée un dict avec des valeurs "par défaut" pour v1 et xyz : {"v1" : 1.0, "xyz" : 1.0}
    4) L'utilisateur a la possibilité de modifier à souhait ces deux variables, mon soft n'ayant plus qu'à évaluer l'expression avec 'eval'.

    Évidemment, c'est le point 2) qui coince ...

  4. #4
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 049
    Points : 1 380
    Points
    1 380
    Par défaut
    recupère l'erreur avec un try/except ...

  5. #5
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    bon ben je vois que les expressions régulières pour résoudre ce genre de problématique.

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 36
    Points : 24
    Points
    24
    Par défaut
    recupère l'erreur avec un try/except ...
    Oui, c'est à ça que je pensais, mais l'erreur ne contient qu'un message du type :
    "name 'v1' is not defined"... ça ne sera pas très classe comme code.

    bon ben je vois que les expressions régulières pour résoudre ce genre de problématique
    Qu'entends-tu par là ?

  7. #7
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    Plus simple !
    bon, je pense que les expressions qui peuvent être saisis par les utilisateurs contiennent des constantes qui correspondent au opérateur et fonction de calcul. le reste étant les variables.
    Il faut dans ce cas considérer que ces constantes sont des mots réservés comme dans tout langage de programmation.

    Ainsi, tu peux splitter ton expression sur les constantes. et définir que les éléments ainsi contenu dans le résultat des splits sont tes nom de variables.

    ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import re
    mask='^([a-zA-Z]?[0-9]?)$' # mask d'expression reguliére définnissant un nom de variable de type 'a1' ou 'a' (pas de aa ou aa1)
    reg=re.compile(mask)
    a='v1^3+45/xyz'#expression a évaluer
    a1=a.split('^')
    b={}# stockage des nom de variables
    for i in a1:
        if re.search(reg,i):
            b[i]=i
        else:
            pass # faire autre chose
     
    print b
    >>{'v1': 'v1'}
    voici une base, a toi de tourner autour. De toute facon tu ne peux pas faire sans imposer un minimum de régles a l'utilisateur quand au nom de variable.
    le mieux serait peut-être de lui dire de définir les variables avec un masque du type "#v1^3+45/#x#y#z.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 36
    Points : 24
    Points
    24
    Par défaut
    Je trouve le "mask" un peu contraignant sur le nom des variables ...

    Quant au "#v1", pareil .......

    J'ai fait un petit code, mais pas très robuste, ni adroit :

    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 getVariables(expr):
        from math import *
        #make a list of safe functions
        safe_list = ['math', 'abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', \
                     'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', \
                     'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
        #use the list to filter the local namespace 
        safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
     
        v = {}
        continuer = True
        error = False
        while continuer:
            try:
                eval(expr, {"__builtins__":None}, safe_dict)
                continuer = False
            except NameError as err:
                vari = err.args[0].split("'")[1]
                v[vari] = safe_dict[vari] = 1.0
            except:
                error = True
                continuer = False
     
        return v, error
    getVariables("a*x**2+34*sin(20)/tz")
    renvoie :
    ({'a': 1.0, 'x': 1.0, 'tz': 1.0}, False)

    Reste à gérer les erreurs "mathématiques" (division par zero, ...) qui ne manqueront pas de se produire à cause du choix de "1.0" comme valeur par défaut pour les variables ...

  9. #9
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    une solution encore plus simple c'est de faire un remplacement des expression mathématique par un carractére unique. Puis un split(), et tu obtient une liste de toute tes variables.
    cependant ca ne marche pas si tu considére que xyz, sont 3 variables equivalent a x*y*z.

    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
    a='a*x**2+34*sin(20)/tz'
    safe_list = ['math', 'abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e',
                     'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf',
                     'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh','*','/','+','-','^','(',')']
     
     
    for i in safe_list:
        a=a.replace(i,'#')
     
    a=a.split('#')
    b={}
    for i in a:
        try:
            int(i)
        except:
            if i.strip()!='':
                b[i]=1.
     
    print b
    {'a': 1.0, 'x': 1.0, 'tz': 1.0}
    Aprés manque plus qu'a voir coté performance.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 36
    Points : 24
    Points
    24
    Par défaut
    Résultat sans appel :

    Pour une boucle de 1000 :
    Ma méthode : 0.26065715056 s
    La tienne : 0.0656890750081 s

    Reste qu'aucune des deux ne gère les erreurs "mathématiques"
    Et il faudrait aussi éprouver leur robustesse...

    Merci à tous pour votre aide, et particulièrement à airod

  11. #11
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    de rien,
    penses au tag "Résolu" sur le post.

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

Discussions similaires

  1. Récupérer des noms de fichier dans une table pour les placer en masque du tfilelist
    Par charliplanete dans le forum Développement de jobs
    Réponses: 11
    Dernier message: 24/08/2011, 17h16
  2. Récupérer les noms des champs dans une requête
    Par Nerziel dans le forum Général Python
    Réponses: 1
    Dernier message: 14/09/2009, 11h29
  3. Réponses: 5
    Dernier message: 11/07/2007, 16h03
  4. Réponses: 8
    Dernier message: 02/11/2005, 14h16
  5. gerer les ' dans une chaine pour eviter erreur sql
    Par Malone dans le forum Langage
    Réponses: 3
    Dernier message: 24/08/2005, 14h27

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