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 :

for key, value in dico ou for item in dico ?


Sujet :

Python

  1. #1
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut for key, value in dico ou for item in dico ?
    Bonjour,

    Suite à ce sujet pourriez vous donner votre avis (et vos explications ) ?

    Merci

  2. #2
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Ou encore

    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
    import time
     
    dico = {}
    liste = []
    for i in range(100000):
        dico[i] = i
     
    tps1 = time.clock()
    for elem in dico:
        liste.append(dico[elem])
    tps2 = time.clock()
    print(tps2 - tps1)
    del(liste[:])
    tps1 = time.clock()
    for key, elt in dico.items():
        liste.append(elt)
    tps2 = time.clock()
    print(tps2 - tps1)
    ?

    Edit : liste = [] > del.

  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
    salut,

    pour ce cas de figure particulier, j'utilise la méthode iteritems:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tps1 = time.clock()
    for key, elt in dico.iteritems():
        liste.append(elt)
    tps2 = time.clock()
    qui a les même perfo que l'itérateur générique du dictionnaire.

    items est à proscrire selon moi dans ce cas (itération) car il y a copie de l'information. mais il me semble que items était destiné à devenir une fonction génératrice (en lieu et place de iteritems). du coup ça dépend peut être des versions de Python.

  4. #4
    Membre expérimenté Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Par défaut
    J'ai fait les tests sur ma machine sous Windows Seven 64bit,
    Avec des versions de Python 32bits :

    2.5 :
    méthode 1 : 0.0182519445094
    méthode 2 : 0.0428708106773

    2.6 :
    méthode 1 : 0.0140861948377
    méthode 2 : 0.040826728089

    2.7 :
    méthode 1 : 0.0132028070224
    méthode 2 : 0.0315123637806

    3.2 :
    méthode 1 : 0.013682909095937069
    méthode 2 : 0.012987721293448757

  5. #5
    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
    ben voilà, ça confirme, items est une génératrice en python 3 visiblement

  6. #6
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    En py3, keys()/values()/items() retournent des vues (views), qui sont un nouveau type d’objets itérables, qui n’entraînent pas de copie des éléments du dict.

    En py2, comme l’a dit kango, il faut systématiquement utiliser iteritems (ou iterkeys/itervalues) dans les boucles (sauf cas particuliers, évidemment), pour éviter cette copie…

  7. #7
    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
    C'est logique que items (ou iteritems en 2.x) soit plus rapide; il n'a pas besoin de faire de recherche dans la table de hashage. J'ai été voir les sources pour m'en assurer (on ne sait jamais comment c'est implémenté); c'est la fonction dictiter_iternextitem dans Objects/dictobject.c.

    Mais en pratique, on voit que le gain n'est pas énorme, sauf cas pathologique (beaucoup de collisions dans la table de hashage):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import time
     
    class BadInt(int):
        def __hash__(self):
            return 42
     
    dico={}
    liste=[]
    for i in range(10000):
        d[BadInt(i)] = i
     
    [suite du script de PauseKawa]
    méthode 1 (iteration+lookup): 2.5869514031419385
    méthode 2 (items): 0.0031533071874036978
    (j'ai diminué le nombre d'itérations car j'ai perdu patience après 5 minutes avec 100000)

  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
    Au passage, on apprend à faire des trucs tordus en lisant les sources
    Code Objects/dictobject.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    static PyDictEntry *
    lookdict(PyDictObject *mp, PyObject *key, register Py_hash_t hash)
    {
    [...]
                    /* The compare did major nasty stuff to the
                     * dict:  start over.
                     * XXX A clever adversary could prevent this
                     * XXX from terminating.
                     */
                     return lookdict(mp, key, hash);

    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
    >>> def doom_key(d, key):
    ... 	class EvilKey:
    ... 		def __hash__(self):
    ... 			return hash(key)
    ... 		def __eq__(self, other):
    ... 			d[key] = None    # major nasty stuff
    ... 			return 0
    ... 		def __str__(self):
    ... 			return str(key)
    ... 	d[EvilKey()] = None
    >>> d={}
    >>> doom_key(d,'test')
    >>> for x in d: print(x)
    ... 
    test
    >>> d['test']
    [...]
    RuntimeError: maximum recursion depth exceeded while calling a Python object
    >>> d['test'] = None
    [...]
    RuntimeError: maximum recursion depth exceeded while calling a Python object
    >>> del d['test']
    [...]
    RuntimeError: maximum recursion depth exceeded while calling a Python object
    >>> d.pop('test')
    [...]
    RuntimeError: maximum recursion depth exceeded while calling a Python object
    >>> d.popitem()
    (<__main__.EvilKey object at 0x070AAE10>, None)
    >>> d
    {} # quand-même !

  9. #9
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    Citation Envoyé par kango Voir le message
    salut,

    pour ce cas de figure particulier, j'utilise la méthode iteritems:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tps1 = time.clock()
    for key, elt in dico.iteritems():
        liste.append(elt)
    tps2 = time.clock()
    qui a les même perfo que l'itérateur générique du dictionnaire.

    items est à proscrire selon moi dans ce cas (itération) car il y a copie de l'information. mais il me semble que items était destiné à devenir une fonction génératrice (en lieu et place de iteritems). du coup ça dépend peut être des versions de Python.
    Citation Envoyé par mont29 Voir le message
    En py3, keys()/values()/items() retournent des vues (views), qui sont un nouveau type d’objets itérables, qui n’entraînent pas de copie des éléments du dict.

    En py2, comme l’a dit kango, il faut systématiquement utiliser iteritems (ou iterkeys/itervalues) dans les boucles (sauf cas particuliers, évidemment), pour éviter cette copie…
    A vrais dire j'étais partis sur ce genre de réflexion et c'est bien l'absence d'iteritem en Python 3 qui me fait préférer for item in dico. Histoire d'avoir du code compatible.
    J'avais aussi penser à iter(dico), compatible lui, mais comme cela ne doit pas faire une grande différence autant rester lisible.

    Pour conclure
    items():
    Une quasi égalité avec for item in dico en Python 3 mais deux fois plus lent en Python 2.
    iteritems():
    Légèrement plus rapide que for item in dico (et égalité avec iter(dico)) mais absent en Python 3.
    Donc autant rester simple : for item in dico.

    Merci à vous

    @+

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

Discussions similaires

  1. log4j:ERROR Could not find value for key log4j.appender
    Par quiquekoi dans le forum Logging
    Réponses: 0
    Dernier message: 28/07/2010, 09h26
  2. Message d'erreur de Mysql "Duplicate entry '0' for key 1"
    Par Alexandrebox dans le forum Requêtes
    Réponses: 4
    Dernier message: 05/02/2010, 16h54
  3. Réponses: 10
    Dernier message: 27/01/2007, 13h54
  4. [message.properties]missing message for key !
    Par jeb001 dans le forum Struts 1
    Réponses: 3
    Dernier message: 16/11/2006, 22h18
  5. [outil] quid de "max seeks for key" et de "max write
    Par Christophe Charron dans le forum Installation
    Réponses: 2
    Dernier message: 31/03/2006, 06h01

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