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 :

Passage de paramètre par variable


Sujet :

Python

  1. #1
    Membre régulier
    Passage de paramètre par variable
    Bonjour à tous,

    Je crée un dictionnaire dans lequel je définis mes paramètres de configuration d'un graphique matplotlib.

    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
    import matplotlib.pyplot as plt
     
    info_graph=tuple()
    info_graph=(
        #graph 0
        {
        "Titre":"rrr",
        "ylabel":'Température [°C]',
        "xlabel":'Temps [s]',
        "xlimits":None,
        "ylimits":'bottom=4',#bug ????
        #"ylimits":[0,12],##y axes limits [min,max] None, sans '' ou ""
        "data0":"Tc2",#"non de la colonne à tracer"
        "data1":"Tc1",#"non de la colonne à tracer"
        "data2":"Tc4",
        "data3":"Tc3",
        "data4":"",
        "data5":"",
        "data6":"",
        "data7":"",
        "data8":"",
        },#fin
        )
     
    plt.plot([1,16,3.4,3,8], label =info_graph[0]["data0"])
    plt.xlabel('s')
    plt.ylabel('°C')
    plt.ylim(info_graph[0]["ylimits"])
    #plt.ylim(bottom = 0)#pas d'erreur
    plt.xlim(info_graph[0]["xlimits"])
    plt.legend(loc='best', ncol=2,fancybox=True)
    plt.show()


    Tout fonctionne comme je le souhaite, sauf avec "bottom = x", ou x est un entier, idem avec "top=x".
    Je n'arrive pas à saisir le pourquoi de l'erreur, donc, ne sais pas la corriger. Une solution qui fonctionne est [0,None], c'est top et tout à fait satisfaisant, mais pourquoi quand "bottom = 0" est passé par une variable il y a l'erreur :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    bottom, top = bottom
     
    ValueError: too many values to unpack (expected 2)


    Je cherche à comprendre pourquoi avec par exemple
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    ylim = "bottom = 0"
    il y a une erreur et donc si
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    ylim = [0,None]
    est une solution ou la solution ^^.

    Merci

  2. #2
    Expert éminent sénior
    Bonjour
    Citation Envoyé par Aelurus_ Voir le message
    Je n'arrive pas à saisir le pourquoi de l'erreur, donc, ne sais pas la corriger. Une solution qui fonctionne est [0,None], c'est top et tout à fait satisfaisant, mais pourquoi quand "bottom = 0" est passé par une variable il y a l'erreur
    Je cherche à comprendre pourquoi avec par exemple
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    ylim = "bottom = 0"
    il y a une erreur et donc si
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    ylim = [0,None]
    est une solution ou la solution ^^.
    Il y a deux soucis distincts dans ton code qui se mélangent au résultat
    1. tout d'abord, la fonction ply.ylim() semble (je ne la connais pas) demander explicitement un tuple (ou un itérable) avec au-moins deux éléments en paramètre "bottom". Donc si tu appelles plt.ylim(4) ça plante tandis que si tu appelles plt.ylim((0, 4)) là ça fonctionne (enfin c'est ce qui s'est passé chez-moi). Et comme ce paramètre se nomme "bottom", tu as le droit d'appeler ta fonction en le nommant => plt.ylim(bottom=(0, 4)).
    2. cette façon d'appeler les fonctions en nommant les paramètres qu'elle attend est une symbolique d'instruction Python. Si par exemple une fonction "fct" attend un paramètre "n", tu peux appeler fct(123) ou bien fct(n=123). Mais tu ne peux pas créer une variable str contenant "n=123" (exemple toto="n=123") et appeler fct(toto) en espérant que Python comprendra qu'il s'agit ici de l'instruction en question. Lui, il pense benoïtement que tu lui passes la chaine littérale "n=123" en paramètre de la fonction. Or c'est ce que tu as fait avec ton "ylimits":'bottom=4'.


    Bon, il y a quand-même des solutions (enfin j'en vois juste 2)...
    1. tu transformes ta string en instruction via eval(). Bon j'ai pas trop testé car j'estime que dans 97% des cas on peut s'en passer mais, pour reprendre mon exemple avec "toto", je pense que fct(eval(toto)) devrait le faire. Mais bon, eval() est une fonction dangereuse en terme de sécurité (ben oui, ça transforme une chaine en instruction donc tu ne maitrises plus forcément ton code !!!) et l'utiliser juste pour ça (en plus que traduire une string en instruction ben ce n'est pas non plus super gratuit en terme de temps d'exec)...
    2. tu reviens aux fondamentaux. C'est quoi les fondamentaux ? C'est comme quand tu débutais et que tu apprenais à passer un paramètre à une fonction. La fonction attend un tuple en paramètre, tu lui passes bêtement un tuple en paramètre (ou bien une variable contenant un tuple ça le fait aussi). Donc tu changes ton dico en "ylimits"<img src="images/smilies/icon_sad.gif" border="0" alt="" title=":(" class="inlineimg" />4, 8)' (ou n'importe quelle valeur pourvu que ce soit un tuple) puis tu appelles tout simplement plt.ylim(info_graph[0]["ylimits"]). Et si vraiment tu veux nommer le paramètre (moi j'aime bien cette approche) ben tu le nommes lors de l'appel => plt.ylim(bottom=info_graph[0]["ylimits"])
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  3. #3
    Membre actif
    Bonjour,

    "bottom = 0" est un objet str, alors que 0 référencé par bottom ( bottom = 0 ) est un objet int ...

  4. #4
    Expert éminent sénior
    Salut,

    Soit une fonction:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> def f(a, b=0):
    ...     print('a', a, 'b', b)
    ...

    on pourra l'appeler avec des paramètres positionnels:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> f(3, 10)
    a 3 b 10
    >>>

    ou des paramètres nommés:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    >>> f(b=10,a=3)
    a 3 b 10


    Si on veut mettre les paramètres positionnels dans une variable on aura un tuple qu'il faudra unpacker lors de l'appel:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> v = 3, 10
    >>> f(*v)
    a 3 b 10

    et si on veut lui passer des paramètres nommées, ce sera un dictionnaire:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> d = dict(b=10, a=3)
    >>> f(**d)
    a 3 b 10

    Constructions qui sont normalement abordées dans tous les bons tutos et qu'on n'est pas supposé avoir oublié lorsqu'on part à coder...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre régulier
    Salut tous,
    Oui wiztricks, je suis d'accord avec toi, bien que ma mémoire me fasse souvent défaut ^^.
    Citation Envoyé par wiztricks Voir le message

    Constructions qui sont normalement abordées dans tous les bons tutos et qu'on n'est pas supposé avoir oublié lorsqu'on part à coder...

    - W
    mais je ne vois pas vraimment le rapport entre les exemples que tu me donnes et la causse de mon soucis, qui est de retourner "bottom = 0" à ylim().

    Car
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    ylim=[0,12]
    plt.ylim(ylim)

    fonctionne comme
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    plt.ylim([0,12])
    , car je passe une liste en argument.

    Effectivement Hominidé, je comprends bien ce que tu me soulignes, qu'avec ylim="bottom = 0", plt.ylim(ylim) n'est pas compris comme plt.ylim(bottom = 0).

    Donc si je suis bien, sois je crée un traitement spécial pour retourner "bottom =" 0 à plt.ylim(), soit je reste avec la liste [0,None] ^^.
    Car en gros ce que je fais c'est
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    plt.ylim(str("bottom = 0"))
    ce qui me retourne la même erreur.

    Je creuse dans cette direction
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    [print("{} {}.".format(cle, valeur)) for cle,valeur in a.items() ]


    mais sans plus de succès.

    Je comprend dèja un peu plus le soucis ^^.

    Citation Envoyé par Sve@r Voir le message
    Bonjour

    C'est comme quand tu débutais et que tu apprenais à passer un paramètre à une fonction.
    ^^,je suis toujours à ce stade .

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    lim = "bottom = 0"
    plt.ylim(eval(lim))

    cela me retourne une erreur de syntaxe,
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      File "<string>", line 1
        bottom = 0
               ^
    SyntaxError: invalid syntax


    mais
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    plt.ylim(bottom=info_graph[0]["ylimits"])
    marche au top avec "ylimits":0.

    Citation Envoyé par Sve@r Voir le message
    Bonjour

    Il y a deux soucis distincts dans ton code qui se mélangent au résultat [list=1]
    [*]tout d'abord, la fonction ply.ylim() semble (je ne la connais pas) demander explicitement un tuple (ou un itérable) avec au-moins deux éléments en paramètre "bottom". Donc si tu appelles plt.ylim(4) ça plante tandis que si tu appelles plt.ylim((0, 4)) là ça fonctionne (enfin c'est ce qui s'est passé chez-moi). Et comme ce paramètre se nomme "bottom", tu as le droit d'appeler ta fonction en le nommant => plt.ylim(bottom=(0, 4)).
    Tu peux écrire plt.ylim(bottom=(0, 4)), je trouve la déclaration pas logique pour le coup. Ecrire plt.ylim(bottom=0) me permet de donner la valeur basse et de laisser la valeur haute libre (donc établie avec la valeur max). Ou inversement plt.ylim(top=600), ou alors on donne les bornes hautes et basses (0,600) ou [0,600], oui les tulples sont mes amis ^^, donc () sera plus économe qu'une liste.

    Merci à tous les trois

  6. #6
    Expert éminent sénior
    Citation Envoyé par Aelurus_ Voir le message
    mais je ne vois pas vraimment le rapport entre les exemples que tu me donnes et la causse de mon soucis, qui est de retourner "bottom = 0" à ylim().
    Normalement, cela aurait du vous suggérer qu'on pouvait écrire:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    d = dict(bottom=0)
    plt.ylim(**d)

    Ce qui ne me semble pas si compliqué...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Expert éminent sénior
    Citation Envoyé par Aelurus_ Voir le message
    Car en gros ce que je fais c'est
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    plt.ylim(str("bottom = 0"))
    ce qui me retourne la même erreur.
    Exactement

    Citation Envoyé par Aelurus_ Voir le message
    ^^,je suis toujours à ce stade .
    Ok, alors petit cours rapide: soit une fonction qui additionne deux valeurs et renvoie le résultat: def add(x, y): return x+y.
    Cette fonction attend deux arguments présumés être des chiffres (en réalité elle peut additionner aussi des strings ou des tuples mais pour l'exemple on va oublier). Tu peux donc l'appeler de différentes façons
    • add(2, 3) (paramètres passés par position)
    • add(x=2, y=3) (paramètres passés par nom)
    • add(y=3, x=2) (paramètres passés par nom et dans ce cas, l'ordre n'a pas d'importance)
    • add(2, y=3) (un paramètre passé par position, l'autre passé par nom mais dans ce cas, les postionnels sont en premier)

    Tu peux aussi très bien créer une (ou deux) variable(s) contenant un chiffre et utiliser cette(ces) variable(s) à la place => toto=2; titi=3; add(toto, titi) avec toutes les déclinaisons ci-dessus (ex add(x=toto, y=titi)). Python remplacera alors "toto" et "titi" par leurs valeurs respectives lors de l'appel. Et ça marche quelle que soit la nature de la variable (même avec un dico => d={"x" : 2, "y" : 3}; add(d["x"], d["y"]). L'important c'est que quand Python remplace d["x"] par sa valeur, il doit y avoir ce qu'attend la fonction (un chiffre).
    Et tu peux même (subtilité Python) créer un tuple contenant 2 valeurs et passer directement ce tuple en paramètre mais en utilisant une syntaxe signifiant "découpe ce tuple en autant de paramètres attendus par la fonction" (unpacking). Ca se fait en utilisant l'étoile sur le tuple => tp=(2, 3); add(*tp).
    Et tu peux aussi passer directement le dico à condition que ses clefs aient le même nom que les paramètres de la fonction (ici "x" et "y") en utilisant la double étoile add(**d). C'était ce qu'a expliqué wiztricks.

    Mais en aucun cas tu peux "simuler" cette syntaxe au travers d'une string style toto="x=2" (même via eval() contrairement à ce que j'ai écrit tantôt comme je le croyais, ce qui explique l'erreur de syntaxe que j'ai eu aussi) car si tu passes "toto" à la fonction, celle-ci se comportera comme d'habitude et récupèrera bêtement sa valeur (une string) sans essayer de traduire cette string en instruction Python.

    Dit plus simplement, l'appel add(x=2, y=3) ne peut absolument pas s'écrire add("x=2", "y=3").
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  8. #8
    Membre régulier
    Oo, effectivement
    Citation Envoyé par wiztricks Voir le message
    Normalement, cela aurait du vous suggérer qu'on pouvait écrire:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    d = dict(bottom=0)
    plt.ylim(**d)

    Ce qui ne me semble pas si compliqué...

    - W
    ce n'est pas compliqué, il est vrai. Par contre bonne ou mauvaise mémoire cette syntaxe (**d) ne me dit rien du tout. Bien entendu sous cette forme elle fonctionne trés bien. Est ce que **d est un équivalent à eval() mais juste pour les dictionnaire ?
    J'ai peu être compris ta solution...
    Donc si je suis bien la logique je pourrais avoir un dictionnaire sous cette forme :
    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
    info_graph=(
        #graph 0
        {
        "Titre":"rrr",
        "col_temp":None,
        "ylabel":'Température [°C]',
        "xlabel":'Temps [s]',
        "xlimits":None,
        "ylimits":{'bottom':0,'top':None}
        "data0":"Tc2",#"non de la colonne à tracer"
        "data1":"Tc1",#"non de la colonne à tracer"
        "data2":"Tc4",
        "data3":"Tc3",
        "data4":"",
        "data5":"",
        "data6":"",
        "data7":"",
        "data8":"",
        },#fin
        )


    Apres relecture je comprend mieux

    Citation Envoyé par wiztricks Voir le message
    Salut,

    ...
    et si on veut lui passer des paramètres nommées, ce sera un dictionnaire:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> d = dict(b=10, a=3)
    >>> f(**d)
    a 3 b 10

    Constructions qui sont normalement abordées dans tous les bons tutos et qu'on n'est pas supposé avoir oublié lorsqu'on part à coder...

    - W
    et cela ne fonctionne que dans une fonction...
    Ce que je n'ai pas vu c'est que dans :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    >>> d = dict(b=10, a=3)
    >>> f(**d)
    a 3 b 10

    je cherchais à b=10 et a=3 comme retour. Je vois que cela fonctionne mais ne comprend pas comment ^^. Car dans :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    d = {'bottom':5,'top':None}
    plt.ylim(**d)

    je ne vois absolument pas plt.ylim(bottom=5, top=None), j'ai l'impression que tu pointes de belle subtilités.

    Merci à toi, car en plus cette solution est beaucoup plus parlante à mon sens que (5,None) ou du moins elle me plait.

  9. #9
    Membre actif
    Bonjour,
    Dans la pratique ça donne ça:
    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
    import matplotlib.pyplot as plt
     
    info_graph=tuple()
    info_graph=(
        {
        "Titre":"rrr",
        "ylabel":'Température [°C]',
        "xlabel":'Temps [s]',
        "xlimits":{'left':0 ,'right': None},
        "ylimits":{'bottom':0, 'top':None},
        "data0":"Tc2",#"non de la colonne à tracer"
        "data1":"Tc1",#"non de la colonne à tracer"
        "data2":"Tc4",
        "data3":"Tc3",
        "data4":"",
        "data5":"",
        "data6":"",
        "data7":"",
        "data8":"",
        },#fin
        )
     
    plt.plot([1,16,3.4,3,8], label =info_graph[0]["data0"])
    plt.xlabel('s')
    plt.ylabel('°C')
    plt.ylim(**info_graph[0]["ylimits"])
    plt.xlim(**info_graph[0]["xlimits"])
    plt.legend(loc='best', ncol=2,fancybox=True)
    plt.show()

  10. #10
    Expert éminent sénior
    Citation Envoyé par Aelurus_ Voir le message
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    lim = "bottom = 0"
    plt.ylim(eval(lim))

    cela me retourne une erreur de syntaxe,
    Exact, je me suis trompé dans la façon de l'utiliser. Il faut le faire dans l'autre sens: lim="plt.ylim(bottom=0)"; eval(lim).
    Mais bon, la plus-value de cette façon de faire face à toutes les autres possibilités d'appel qu'on t'a montré tantôt reste à mon avis très négligeable.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  11. #11
    Expert éminent sénior
    Salut,

    Citation Envoyé par Aelurus_ Voir le message
    Par contre bonne ou mauvaise mémoire cette syntaxe (**d) ne me dit rien du tout. Bien entendu sous cette forme elle fonctionne trés bien. Est ce que **d est un équivalent à eval() mais juste pour les dictionnaire ?
    Vous ne pouvez pas ne pas l'avoir vue!
    Relisez la documentation de pyplot.ylim les arguments sont (*args, **kwargs).
    Et cela est décrit dans le tutoriel Python avec les autres subtilités des paramètres de fonction.

    Et non ce n'est pas équivalent eval qui interprète une chaîne de caractères alors qu'ici on fait de l'unpacking d'un dictionnaire.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  12. #12
    Membre actif
    Citation Envoyé par Sve@r Voir le message
    Exact, je me suis trompé dans la façon de l'utiliser. Il faut le faire dans l'autre sens: lim="plt.ylim(bottom=0)"; eval(lim).
    Mais bon, la plus-value de cette façon de faire face à toutes les autres possibilités d'appel qu'on t'a montré tantôt reste à mon avis très négligeable.
    D'autant que la string "button=0" était issu d'une gestion/formation erronée du dictionnaire .

  13. #13
    Membre régulier
    Mais oui, je l'ai vu "(*args, **kwargs)", je m'aperçois que je ne comprenais pas ce que cela voulait dire. Je vais aller regarder ce tutos.
    Merci

    "
    Citation Envoyé par wiztricks Voir le message
    Salut,

    Vous ne pouvez pas ne pas l'avoir vue!
    Relisez la documentation de pyplot.ylim les arguments sont (*args, **kwargs).
    Et cela est décrit dans le tutoriel Python avec les autres subtilités des paramètres de fonction.

    Et non ce n'est pas équivalent eval qui interprète une chaîne de caractères alors qu'ici on fait de l'unpacking d'un dictionnaire.

    - W
    Hominidé, oui merci pour le xlimits

###raw>template_hook.ano_emploi###