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 :

Nettoyage propre d'un tableau [Python 2.X]


Sujet :

Python

  1. #1
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut Nettoyage propre d'un tableau
    Bonjour

    J'ai un souci existentiel à propos de la meilleure façon de nettoyer un tableau.
    En effet, vaut-il mieux écrire del tab[:] ou plus simplement tab=autre_chose en laissant le gb se débrouiller tout seul...?

    J'ai testé les deux façons de faire de cette façon
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class toto(object):
        def __init__(self): print "init (%s)" % self
        def __del__(self): print "del (%s)" % self
    # class toto
     
    tab=[toto() for x in range(5)]
    print "tab créé"
    del tab[:]    # Ou bien tab=None
    print "tab supprimé"

    Mais je ne vois aucune différence. Si l'un d'entre vous avait des conseils à ce sujet...

    Merci à tous
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  2. #2
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2013
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2013
    Messages : 156
    Points : 218
    Points
    218
    Par défaut
    Bonjour,

    Si je comprend bien la question, il y a bien une différence,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> a = [1, 2, 3]
    >>> b = a
    >>> a = []
    >>> print(a)
    []
    >>> print(b)
    [1, 2, 3]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    >>> a = [1, 2, 3]
    >>> b = a
    >>> del a[:]     
    >>> print(a)
    []
    >>> print(b)
    []
    >>> a is b
    True
    Je vais quand même t'embêter encore un peu plus en te donnant une troisième solution.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    # Comparaison de l=list(range(1000))" "b=l[:];del b[:] VS l=list(range(1000))" "b=l[:];b[:] = []
     
    $ python -mtimeit "l=list(range(1000))" "b=l[:];del b[:]"
    10000 loops, best of 3: 29.8 usec per loop
    $ python -mtimeit "l=list(range(1000))" "b=l[:];b[:] = []"
    10000 loops, best of 3: 28.7 usec per loop
     
    (python 2.5, à tester avec votre python)

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    La différence est entre déréférencer la liste et déréférencer les objets la liste. Et si on fait abstraction de l'objet (liste) supplémentaire, ici, le GC ne bosse pas vraiment: les objets sont détruits lorsque le nombre de références passe à 0.
    Il bosse surtout lorsqu'il y a des cycles i.e. il n'y a plus vraiment de références qu'entre les objets eux-mêmes.

    Après entre "del tab[:]" et "tab=autre_chose" est plutôt dans vider la liste plutôt qu'assigner à tab autre chose. Ce qui n'aura pas le même effet pour les autres variables associées au même objet (mais c'est plus un pb de GC).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> a = b = [1, 2, 3]
    >>> del a[:]
    >>> b
    []
    >>> a
    []
    on a "vidé" la liste associée à a et b.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> a = b = [1, 2, 3]
    >>> a = []
    >>> a
    []
    >>> b
    [1, 2, 3]
    >>>
    on a assigné une nouvelle liste à a mais l'ancienne, côté b, est inchangée.

    Dit autrement, les deux constructions adressant des problèmes différents, difficile de savoir laquelle est la meilleure: çà dépend du contexte.

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

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur banc de test
    Inscrit en
    Mai 2014
    Messages
    199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur banc de test
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mai 2014
    Messages : 199
    Points : 482
    Points
    482
    Par défaut
    Bonsoir,

    une autre méthode d'investigation est d'étudier la transformation du code en bytecode à l'aide de la librairie dis.

    Un exemple ici : http://stackoverflow.com/a/12673195

    Puisque timeit retourne pratiquement le même temps de traitement sur les deux méthodes, avec dis on saura exactement le nombre d'instructions que prennent les opérations.

    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
    import dis # Disassembler for Python bytecode
    import sys
     
    def f_del():
    	l = list(range(1000))
    	b=l[:]
    	del b[:]
    	return # Pour séparer les instructions de retour de fonction
     
    def f_slice():
    	l = list(range(1000))
    	b=l[:]
    	b[:] = []
    	return # Pour séparer les instructions de retour de fonction
     
    print("Python {} on {}".format(sys.version, sys.platform))
    print("\nf_del")
    dis.dis(f_del)
    print("\nf_slice")
    dis.dis(f_slice)
    On obtient ceci :

    Testé sur Windows 7 Home x64

    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
    33
    34
    35
    36
    37
    38
    Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
     
    f_del
      5           0 LOAD_GLOBAL              0 (list)
                  3 LOAD_GLOBAL              1 (range)
                  6 LOAD_CONST               1 (1000)
                  9 CALL_FUNCTION            1
                 12 CALL_FUNCTION            1
                 15 STORE_FAST               0 (l)
     
      6          18 LOAD_FAST                0 (l)
                 21 SLICE+0
                 22 STORE_FAST               1 (b)
     
      7          25 LOAD_FAST                1 (b)
                 28 DELETE_SLICE+0
     
      8          29 LOAD_CONST               0 (None)
                 32 RETURN_VALUE
     
    f_slice
     11           0 LOAD_GLOBAL              0 (list)
                  3 LOAD_GLOBAL              1 (range)
                  6 LOAD_CONST               1 (1000)
                  9 CALL_FUNCTION            1
                 12 CALL_FUNCTION            1
                 15 STORE_FAST               0 (l)
     
     12          18 LOAD_FAST                0 (l)
                 21 SLICE+0
                 22 STORE_FAST               1 (b)
     
     13          25 BUILD_LIST               0
                 28 LOAD_FAST                1 (b)
                 31 STORE_SLICE+0
     
     14          32 LOAD_CONST               0 (None)
                 35 RETURN_VALUE


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
     
    f_del
      7          25 LOAD_FAST                1 (b)
                 28 DELETE_SLICE+0
     
    f_slice
     13          25 BUILD_LIST               0
                 28 LOAD_FAST                1 (b)
                 31 STORE_SLICE+0
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32
     
    f_del
      5           0 LOAD_GLOBAL              0 (list)
                  3 LOAD_GLOBAL              1 (range)
                  6 LOAD_CONST               1 (1000)
                  9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 15 STORE_FAST               0 (l)
     
      6          18 LOAD_FAST                0 (l)
                 21 LOAD_CONST               0 (None)
                 24 LOAD_CONST               0 (None)
                 27 BUILD_SLICE              2
                 30 BINARY_SUBSCR
                 31 STORE_FAST               1 (b)
     
      7          34 LOAD_FAST                1 (b)
                 37 LOAD_CONST               0 (None)
                 40 LOAD_CONST               0 (None)
                 43 BUILD_SLICE              2
                 46 DELETE_SUBSCR
     
      8          47 LOAD_CONST               0 (None)
                 50 RETURN_VALUE
     
    f_slice
     11           0 LOAD_GLOBAL              0 (list)
                  3 LOAD_GLOBAL              1 (range)
                  6 LOAD_CONST               1 (1000)
                  9 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
                 15 STORE_FAST               0 (l)
     
     12          18 LOAD_FAST                0 (l)
                 21 LOAD_CONST               0 (None)
                 24 LOAD_CONST               0 (None)
                 27 BUILD_SLICE              2
                 30 BINARY_SUBSCR
                 31 STORE_FAST               1 (b)
     
     13          34 BUILD_LIST               0
                 37 LOAD_FAST                1 (b)
                 40 LOAD_CONST               0 (None)
                 43 LOAD_CONST               0 (None)
                 46 BUILD_SLICE              2
                 49 STORE_SUBSCR
     
     14          50 LOAD_CONST               0 (None)
                 53 RETURN_VALUE


    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
    Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)] on win32
     
    f_del
      7          34 LOAD_FAST                1 (b)
                 37 LOAD_CONST               0 (None)
                 40 LOAD_CONST               0 (None)
                 43 BUILD_SLICE              2
                 46 DELETE_SUBSCR
     
    f_slice
     13          34 BUILD_LIST               0
                 37 LOAD_FAST                1 (b)
                 40 LOAD_CONST               0 (None)
                 43 LOAD_CONST               0 (None)
                 46 BUILD_SLICE              2
                 49 STORE_SUBSCR
    Les numéros de la première colonne sont les lignes dans le code python.

    Avec python 2.7.11 ce qui change :

    f_del :
    1. LOAD_FAST: b
    2. DELETE_SLICE+0


    f_slice:
    1. BUILD_LIST
    2. LOAD_FAST: b
    3. STORE_SLICE+0


    Avec python 3.5.1 :
    f_del :
    1. DELETE_SUBSCR


    f_slice:
    1. BUILD_LIST
    2. STORE_SUBSCR


    On a toujours une instruction en plus avec la méthode de de remplacement, mais le temps d'exécution reste quasiment identique.

    Ce qui est intéressant c'est la différence entre python 2 et 3:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import timeit
    timeit.timeit("f_del()", "from __main__ import f_del", number=int(1e5))
    timeit.timeit("f_slice()", "from __main__ import f_slice", number=int(1e5))
    Avec python 2.7.11 : On a 2 et 3 instructions
    f_del: 1.346 s
    f_slice: 1.346 s


    Avec python 3.5.1 : On a 5 et 6 instructions et ça se ressent:
    f_del: 1.745 s
    f_slice: 1.776 s


    Je ne sais pas à quoi servent les deux instructions LOAD_CONST, peut-être pour les paramètres du slicing start:end ?

    Il y a sans doute une syntaxe plus efficace en python 3.


    Exemple avec la méthode clear()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f_clear():
    	l = list(range(1000))
    	b=l[:]
    	b.clear()
    	return # Pour séparer les instructions de retour de fonction
     
    print("\nf_clear")
    dis.dis(f_clear)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     19          34 LOAD_FAST                1 (b)
                 37 LOAD_ATTR                2 (clear)
                 40 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
                 43 POP_TOP
    On gagne une instruction mais le temps n'est pas meilleur :

    f_del: 1.757
    f_slice: 1.759
    f_clear: 1.769


    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    # Python 3
    import dis # Disassembler for Python bytecode
    import sys
    import timeit
     
    def f_del():
    	l = list(range(1000))
    	b=l[:]
    	del b[:]
    	return # Pour séparer les instructions de retour de fonction
     
    def f_slice():
    	l = list(range(1000))
    	b=l[:]
    	b[:] = []
    	return # Pour séparer les instructions de retour de fonction
     
    def f_clear():
    	l = list(range(1000))
    	b=l[:]
    	b.clear()
    	return # Pour séparer les instructions de retour de fonction
     
    print("Python {} on {}".format(sys.version, sys.platform))
    print("\nf_del")
    dis.dis(f_del)
    print(round(
            timeit.timeit("f_del()", "from __main__ import f_del", number=int(1e5)),
            3
    ))
    print("\nf_slice")
    dis.dis(f_slice)
    print(round(
            timeit.timeit("f_slice()", "from __main__ import f_slice", number=int(1e5)),
            3
    ))
    print("\nf_clear")
    dis.dis(f_clear)
    print(round(
            timeit.timeit("f_clear()", "from __main__ import f_clear", number=int(1e5)),
            3
    ))

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Merci de vos avis.
    Donc déjà je vais préciser quelques points: dans mon cas précis il n'y a aucune notion de recopie. J'ai retrouvé un de mes anciens codes de débutant où j'avais écrit une class style
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class truc:
        def __init__(self):
            self.__tabID=[]
     
        def clear(self):
            del self.__tabId[:]
     
        def load(self):
            ...
            self.__tabId=[...]
    # class
    Et c'est là que je me suis demandé si le del de mon clear() était vraiment pertinent vu qu'au chargement je réinitialisais totalement mon tableau ; d'où ma question.


    Citation Envoyé par wiztricks Voir le message
    Dit autrement, les deux constructions adressant des problèmes différents, difficile de savoir laquelle est la meilleure: çà dépend du contexte.
    Ok. Déjà là ça me rassure quand je pense que le del devient totalement inutile.

    Citation Envoyé par IPreferCSharp Voir le message
    Bonjour,
    J'aime bien ton pseudo. Enfin chacun ses choix

    Citation Envoyé par IPreferCSharp Voir le message
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    $ python -mtimeit "l=list(range(1000))" "b=l[:];b[:] = []"
    Ce ne devrait pas être plutôt
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    $ python -mtimeit "l=list(range(1000))" "b=l[:];b = []"
    ???

    En tout cas chez-moi (python 2.7.11) voilà ce que ça donne...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ python -mtimeit "l=list(range(10000));b=l[:];del b[:]"
    10000 loops, best of 3: 122 usec per loop
     
    $ python -mtimeit "l=list(range(10000));b=l[:];b=None"
    10000 loops, best of 3: 124 usec per loop

    Très sensiblement pareil quoi. Et pareil pour le b[:]=[]...






    Citation Envoyé par YCL-1 Voir le message
    une autre méthode d'investigation est d'étudier la transformation du code en bytecode à l'aide de la librairie dis.
    Super sympa . Un nouveau truc à explorer
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. [XL-2010] Nettoyage cellule vide dans tableau sur excel 2010
    Par tepuy dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 30/08/2015, 11h20
  2. Nettoyage de tableau
    Par Sve@r dans le forum Général Python
    Réponses: 2
    Dernier message: 30/01/2013, 21h19
  3. Nettoyage d’un tableau
    Par neonecc dans le forum Collection et Stream
    Réponses: 8
    Dernier message: 16/06/2008, 14h12
  4. Recupération propre des données d'un tableau
    Par Invité dans le forum Langage
    Réponses: 8
    Dernier message: 04/12/2007, 22h53
  5. Réponses: 4
    Dernier message: 13/05/2002, 16h43

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