Affectation, variable et eval en python

Bonjour,

je dispose d'une variable, dont le nom est contenu dans une chaîne de caractère $a$ et j'aimerais affecter la valeur 2 à cette variable, j'ai donc tenté un $eval(a+"=2")$, mais cela ne donne rien.
De même $eval("a=3")$ n'affecte pas la valeur 3 à la variable a mais renvoie une erreur. J'imagine que cela signifie que la commande eval attend un résultat, comme par exemple dans $eval("2+3")$, et que la commande d'affectation $a=3$ ne renvoie rien.
Quelqu'un saurait-il comment effecteur cette opération.

D'avance merci.

Bonne journée

F.

Réponses

  • a=int(a) ?
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • Ma variable $a$ n'est pas un entier, mais une classe. Du coup, j'ai bricolé un truc avec une chaîne du type "setattr(a,'att',valeur)", qui elle s'évalue correctement.
    Par contre, je rencontre un autre souci:
    dans une fonction $f$ d'une variable $a$,
    j'utilise une variable locale $b$ fonction de $a$, que je dois utiliser pour modifier $a$. Or entre la définition de $b$ et son utilisation, la fonction modifie la valeur de $a$ et donc celle de $b$. D'où ma question, comment affecter une valeur fonction de $a$ à $b$ de façon à ce que la modification de $a$ n'entraîne pas celle de $b$. Un exemple :
    l=[1,2,3]
    m=l
    l.append(4)
    m
    [1,2,3,4]
    
    et une précision, $a$ n'est pas une liste mais une classe.

    Bonne journée
  • m=l.copy() par exemple ou m=[e for e in l].
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • Merci,

    mais la méthode copy() est elle propre aux listes ou est-elle une méthode générale à tous les objets ?

    Bonne journée

    F.
  • Elle est générale aux objets qui ont la méthode copy. :-D
    Je pense que c’est le cas des objets non hashables comme les listes, les ensembles ou les dictionnaires.
    Regarde en tapant dir([1,2]).
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • Je crois que tu confonds `eval` avec `exec`.
    La chose suivante a l'air de fonctionner
    a = "maVariable"
    exec(a + "=2")
    print(maVariable) # affiche 2
    
  • Merci,

    pour la méthode copie vu qu'il s'agit d'un type que j'ai crée, elle ne doit pas y être ;-)
    si j'ai bien suivi, eval envoie une expression et attend un résultat, tandis qu'exec exécute une instruction sans rien attendre en retour ?

    Bonne soirée

    F.
  • Tu peux créer la méthode copy si tu le souhaites.
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • si j'ai bien suivi, eval envoie une expression et attend un résultat, tandis qu'exec exécute une instruction sans rien attendre en retour ?

    Oui c'est ça. Par contre, ça paraît assez bizarre et assez peu recommandé ce que tu veux faire (nommer une variable dans une string, notamment). Les méthodes eval et exec sont assez dangereuses, comme je l'ai expliqué récemment.

    Peux-tu donner plus de contexte (pour tes 2 soucis, je t'avoue ne pas tout suivre au second) ?

    Edit : typo
  • Ha, l’appeau à sebsheep a fonctionné. :-D
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • (c'était trop tentant :) )
  • Bonjour,

    j'essayais dans un arbre binaire de recherche de supprimer un entier $n$ donné, pour celà je cherchais le chemin menant à $n$, que j'obtenais sous la forme d'une chaîne de caractères $"a.fg.fd.fg"$, l'objet $a$ étant un objet de type noeux, comportant trois attributs : racine,fg et fd. Suivant la nature de $"a.fg.fd.fg"$, j'effectuais ensuite l'opération adéquate sur l'arbre initial via la commande eval ou exec.

    Globalement je pense m'en être sorti, mais je ne vois pas comment me dispenser d'utiliser eval ou exec.

    Bonne journée

    F.
  • Le mot clé existe, tu n’as pas à t’en dispenser a priori, c’est juste qu’il faut faire très attention.
    Algebraic symbols are used when you do not know what you are talking about.
            -- Schnoebelen, Philippe
  • Suivant la nature de "a.fg.fd.fg", j'effectuais ensuite l'opération adéquate sur l'arbre initial via la commande eval ou exec.
    Si tu es obligé de faire ainsi, c'est probablement que la classe utilisée pour représenter les arbres ne contient pas les méthodes adéquates pour modifier comme tu veux le faire... C'est donc elle qu'il faut modifier !
  • Le mot clef est dans le langage, mais son usage par des débutant révèle souvent une erreur de design, l'utilisation d'une mauvaise structure donnée et/ou un code très difficile à maintenir et debugger.

    Pour le debuggage : si ta chaîne "a.fg.fg.fd" est bugguée pour une raison ou une autre, c'est assez délicat : l'erreur n'apparaîtra que très tardivement (au moment du "eval") et il faut alors chercher ce que ne va pas dans un code généré dynamiquement. Et il y a pleins de raisons pour que ta chaîne devienne foireuse : tu changes ta classe Noeud et "fg" devient "fils_gauche", ta variable "a" devient "arbre", ...

    Pour le design : pourquoi as-tu besoin de ce chemin ? Lorsque tu recherches ton entier, tu as ton noeud, pourquoi s'embêter à construire le chemin pour ensuit re-accéder à ton noeud ?

    Pour la structure de donnée : si tu veux stocker un chemin, le plus adapté semble une liste des directions prises. Cette liste peut ensuite être convertie en chaine de caractères si on veut l'afficher en console, ou alors traitée par un autre programme pour afficher une succession d'images, ou traitée pour faire des stats sur le nombre de "gauche"/"droite"....

    Si tu as vraiment besoin de ce chemin (j'en doute), tu peux faire une méthode (récursive) qui te renvoie deux choses : l'entier qui t'intéresse et la liste des directions à prendre pour accéder à cet entier (de la forme ["G", "D", "G"] par exemple). Je te le laisse en exercice, n'hésite pas à nous demander si tu es bloquée.

    Mais avant tout : pourquoi as-tu besoin de ce chemin ?
  • Bonjour,

    merci de vos réponses.
    Je n'ai pas besoin de ce fameux chemin pour trouver un entier n dans mon arbre, par contre j'en ai besoin pour trouver l'entier suivant n ou pour supprimer n.
    Pour obtenir ce chemin, j'effectue effectivement une recherche récursive et le chemin que j'obtiens est dans un premier temps sous forme de liste .
    Si par exemple, je veux supprimer l'entier n de mon arbre et que n n'est pas une feuille, je suis obligé de bricoler avec des eval/exec pour réussir à supprimer n.
    Le plus propre serait sans doute de réussir à créer une méthode liée à la classe noeud prenant pour argument la liste de direction et renvoyant le suivant ou supprimant. Je vais essayer de creuser dans cette direction et je reviendrais vers vous en cas de problème.

    Encore merci et bonne journée

    F.
  • Donc en fait tu veux te promener dans ta structure d'arbre. Peut-être te manque-t-il l'attribut "parent" dans ta classe noeud te permettant de "remonter dans l'arbre" (ce "parent" étant None lorsque le noeud est une racine) ? Peut-être as tu besoin également de savoir qui est le "frère" d'un noeud (potentiellement None aussi).

    Utiliser une liste de chemin ne me semble pas adapté ici, il faut que tu puisses te promener dans ton arbre avec un truc du genre (avec nécessité de tester à chaque fois les None***) :
    noeud.frere.fg.fd....
    
    Peux-tu nous copier/coller ta classe Noeud ?
    Le plus propre serait sans doute de réussir à créer une méthode liée à la classe noeud prenant pour argument la liste de direction et renvoyant le suivant ou supprimant.

    Que veut dire "suivant" dans le contexte d'un arbre ?

    D'une façon plus générale, quand tu as un soucis, tente de décrire ton soucis originel, pas le "soucis que tu as avec la solution X". Ça permettra d'avoir beaucoup plus vite une aide pertinente. Par exemple ici tu aurais pu poster
    j'ai une structure d'arbre avec cette classe Noeud :[...du code ....], je veux pouvoir supprimer le noeud qui vérifie .... . J'ai tenté ceci [...ton code avec du eval....], mais je suis bloqué(e?)

    [size=x-small]*** si seulement on avait une "do notation" comme en Haskell....[/size]
  • Bonjour,

    une précision importante l'arbre que j'utilise est un arbre binaire de recherche. Alors le code de la classe noeud est:
    class noeud:
        def __init__(self,info=[], **kwargs):
            self.info=info      
            for key in kwargs:
                #print(key,kwargs[key])
                if not isinstance(kwargs[key],int):
                    setattr(self,key,kwargs[key])
                else:
                    setattr(self,key,noeud(kwargs[key]))
        
        def ajoutr(self,n):
            if isinstance(n,int):
                self.info=n
            else:
                self.info=n.info
            if hasattr(n,'fg'):
                self.fg=n.fg
            if hasattr(n,'fd'):
                self.fd=n.fd    
        
        
        def isf(self):
            if hasattr(self,'fg') or hasattr(self,'fd'):
                return(False)
            else:
                return(True)
        def ise(self):
            return(self.isf() and self.info==[])
        
        def ajoutg(self,n):
            if isinstance(n,int):
                self.fg=noeud(n)
            else:
                self.fg=n
                
        def ajoutd(self,n):
            if isinstance(n,int):
                self.fd=noeud(n)
            else:
                self.fd=n
    

    La fonction pour supprimer un noeud est:
    def suppr(a,n):
        chem=chemin(a,n)
        t=chem2str(chem)
        b=eval(t)
        if n==b.info:
            if b.isf():
                c=t+".ajoutr(noeud())"
                print(c)
                eval(c)
            if hasattr(b,'fg') and not hasattr(b,'fd'):
                c=b.fg
                c1=t+".ajoutr(c)"
                c2="delattr("+t+",'fg')"
                eval(c2)
                eval(c1)
                return(a)
            elif not hasattr(b,'fg') and hasattr(b,'fd'):
                c=b.fd
                c1=t+".ajoutr(c)"
                c2="delattr("+t+",'fd')"
                eval(c2)
                eval(c1)
                return(a)
            elif hasattr(b,'fg') and hasattr(b,'fd'):
                c=b.fg
                m=amax(c)
                print(m)
                suppr(a,m)
                c1="setattr("+t+",'info',"+str(m)+")"
                eval(c1)
                return(a)
    

    où la fonction chemin est:
    def chemin(a,n):
        #print("appel rec")
        if not a.ise():
            if a.info==n:
                #print("n trouve")
                return([])
            else:
                if n<a.info and hasattr(a,'fg'):
                    return(['fg']+chemin(a.fg,n))
                if n>a.info and hasattr(a,'fd'):
                    return(['fd']+chemin(a.fd,n))     
                if a.isf():
                    return([])    
    
    
    def chem2str(chem):
        if len(chem)>0:
            t='a.'+'.'.join(chem)
        else:
            t='a'
        return(t)
    

    @sebsheep, si j'ai bien compris ce que tu m'as dit, il conviendrait dans un premier temps modifier la classe noeud et d'y ajouter un attribut parent, puis de faire en sorte que la fonction suppr devienne une méthode de la classe noeud ?

    Merci et bonne journée

    F.
  • Ahem, on a ouvert la boîte de Pandore j'ai l'impression...

    Ta structure me semble inutilement compliquée. Pourquoi utiliser les getattr et setattr et utiliser les arguments variables ? Ça ne me semble pas adapté ici (ça l'est dans certaines situations, mais ici, je n'ai pas l'impression).

    Tu veux juste un arbre binaire dont les noeuds stockent un entier ? Bon ben je pense que le plus simple est d'avoir un noeud comme cela :
    class NoeudABR:
        def __init__(self, n, parent):
            self.n = n
            self.gauche = None
            self.droit = None
            self.parent = parent
    
        def get_frere(self):
             if self.parent is None :
                   return None
             if self.parent.gauche is self :
                   return self.parent.droit
              return self.parent.gauche
    
        def rechercher(self, valeur):
             """Renvoie  le noeud dont le "n" est "valeur" ou None si la valeur n'est pas dans l'arbre"""
             ...
      
        def suivant(self):
             """ Renvoie le noeud contenant la valeur suivant self.n ou None s'il n'y a pas de suivant."""
             ...
    
        def precedent(self):
             ...
        def inserer(self, valeur):
            """insère un noeud dans l'arbre enraciné en "self" en respectant la sturcture d'ABR"""
            ... 
    
    
    Je ne sais pas s'il faut conserver "supprimer" comme une méthode ou comme une fonction externe à la classe (je n'ai plus assez l'algo de suppression en tête). De même, je ne sais plus si on a vraiment besoin de "parent" ou "get_frere" (les méthodes "suivant/précédent" doivent suffire je pense.

    Mais bon, en partant avec un code comme ça, tu auras déjà beaucoup plus facile de te dépatouiller.
Connectez-vous ou Inscrivez-vous pour répondre.