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 :

comportement que je ne comprend pas


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Novembre 2008
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 46
    Par défaut comportement que je ne comprend pas
    Bonjour,

    j'ai un comportement que je ne comprend pas dans ce petit exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def test(toto = [0.,1.]):
        toto.append(2.)
        print toto
        return toto
     
    test1 = test()
    print 'test1',test1
     
    test2 = test()
    print 'test2',test2
    Pourquoi les deux appelle à la fonction test ne renvoient pas la même chose !!!
    a savoir
    [0.,1.,2.]
    puis [0.,1.,2.,2.] !

    Pour que ca fonctionne je fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def test(toto = None):
        if toto == None : toto = [0.,1.]     
        toto.append(2.)
        print toto
        return toto
    On m'avait déjà donné cette astuce dans un autre cas de figure.

    Quelqu'un saurait m'expliquer pourquoi la première version n'est pas correct, et pourquoi les concepteurs de python ont souhaité ceci?

    Cordialement,

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 159
    Par défaut
    Salut,
    C'est très connu, voir ici http://docs.python.org/tutorial/cont...rgument-values le paragraphe "important warning".

    Python n'évalue les arguments par défaut qu'une seule fois, lors des appels suivants de la fonction il se contente d'accéder à l'objet instancié la première fois.
    Si l'objet en question est mutable (comme une liste), il peut très bien avoir été modifié entretemps (ce qui est le cas dans ton exemple).
    Je ne sais pas ce qui a motivé ce fonctionnement, mais je suppose qu'il s'agissait à l'origine plus d'une facilité d'implémentation qu'autre chose.

    PS : en tous cas, la méthode que tu utilises pour contourner le problème correspond bien à ce qui est recommandé dans le "python tutorial"

  3. #3
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    bonjour,

    en fait l'explication tient en une seule phrase:

    les valeurs par défaut des arguments d'une fonction sont crées une seule fois à la déclaration de cette dernière.

    donc, en affectant un type muable en valeur par défaut, cette valeur reste la même pendant toute la durée de vie de la fonction.

    ce qui explique dans ton cas que la valeur de la liste change au cours du temps et des appels à la fonction.

    la solution consiste à ne pas affecter des types muables en valeur par défaut.

    ça c'est pour le comment. pour le pourquoi, je ne suis pas dans les petits papiers des développeurs de Python. mais, de mon point de vue il ne s'agit pas d'un choix en tant que tel mais plus de la conséquence d'un autre choix, plus important, fait sur l'architecture générale de Python.

    edit: grilled

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 748
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 748
    Par défaut
    Salut,
    La valeur des arguments par défaut n'est évaluée qu'à la definition de la fonction i.e. une fois... Ce qui peut provoquer des surprises lorsqu'il est "mutable" (une "list").

    C'est expliqué dans la doc :
    Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:
    Et aussi dans la description de ce qu'est une "fonction" en Python
    Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended.
    Côté design (pourquoi) la question est comment traiter l'initialisation d'arguments par défaut avec un type "mutable"...
    Le choix Python est surprenant pour la première fois qu'on tombe dessus, mais il est assez cohérent avec 'tout est objet' - et les fonctions aussi - et le traitement des "valeurs"/"collections".
    Lire aussi effbot qui donne pas mal d'exemples.
    - W
    PS: Je n'ai pas trouvé de comparatif avec d'autres langages objets sur le traitement des paramètres par défaut: peu le proposent.
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre averti
    Inscrit en
    Novembre 2008
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Novembre 2008
    Messages : 46
    Par défaut
    Merci à tous pour vos réponse très claire !

    Je ne trouve pas cela très naturel, mais bon, on peut bien pardonner ceci pour tout le reste !

    Merci encore

  6. #6
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    PS: Je n'ai pas trouvé de comparatif avec d'autres langages objets sur le traitement des paramètres par défaut: peu le proposent.
    Pour information C++ propose les arguments par défaut depuis sa création en 1983, alors que Python ne devait voir le jour que 7 ans plus tard. En outre le comportement est, de mon point de vue plus naturel. Il me semble que le c'est le choix d'implémentation des ppd en Python qui implique ce comportement somme toute bizarre.
    Code C++ : 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
    #include <iostream>
     
    using namespace std;
    int fonc(int n2=0)
    {
        n2++;
        return n2;
    }
     
    int main()
    {
       cout<<fonc()<<"\n";
       cout<<fonc();
     
        return 0;
    }
    Le programme affiche bien
    1
    1
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 748
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 748
    Par défaut
    Salut,

    Pour information C++ propose les arguments par défaut depuis sa création en 1983, alors que Python ne devait voir le jour que 7 ans plus tard.
    foo(p1='toto', p2='tutu') en Python n'a pas la même sémantique qu'en C++. En C++, les paramètres sont positionnels, alors qu'en Python, ils sont aussi "nommés". i.e. foo(p2='x') est possible en Python pas en C++


    En outre le comportement est, de mon point de vue plus naturel. Il me semble que le c'est le choix d'implémentation des ppd en Python qui implique ce comportement somme toute bizarre.
    Dans l'exemple que vous proposez le type d'un int n'est pas mutable, en Python çà fonctionnerait pareil.

    C# et DELPHI proposent aussi cela.
    Mais, je n'ai pas trouvé de comparatif sur les détails des subtilités sur 'que se passe-t-il lorsque le paramètre par défaut est 'mutable'.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  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
    Cet exemple devrait être plus concluant (mon C++ est un peu rouillé, désolé si c'est une horreur):
    Code C++ : 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
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    vector<int> *func(int x, vector<int> *v = new vector<int>)
    {
    	v->push_back(x);
    	return v;
    }
     
    int main()
    {
    	vector<int> *V1, *V2;
    	V1 = func(1); cout << &V1 << endl;
    	V2 = func(2); cout << &V2 << endl;
    	for (vector<int>::iterator x=V1->begin(); x < V1->end(); ++x)
    		cout << *x << " ";
    	return 0;
    }
    Résultat:
    Les adresses des vecteurs retournés sont différentes, et le premier vecteur n'a pas été modifié après le second appel. Les valeurs par défaut ne sont donc pas évaluées lors de l'initialisation statique mais lors de chaque appel, contrairement à Python.

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

Discussions similaires

  1. Requête ayant un comportement que je ne comprends pas
    Par Kropernic dans le forum Développement
    Réponses: 0
    Dernier message: 08/09/2011, 12h25
  2. Réponses: 3
    Dernier message: 18/01/2010, 13h48
  3. comportement de ifstream que je ne comprend pas
    Par Michaeljackfan dans le forum Langage
    Réponses: 5
    Dernier message: 19/09/2009, 14h21
  4. [thread][methodologie]Quelque chose que je ne comprends pas!
    Par norkius dans le forum Général Java
    Réponses: 5
    Dernier message: 16/03/2005, 14h01
  5. [Rave] un message que je ne comprends pas
    Par Clotilde dans le forum Rave
    Réponses: 2
    Dernier message: 30/09/2003, 21h46

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