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 :

Mon code est-il pythonique


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 215
    Par défaut Mon code est-il pythonique
    Je m'initie en ce moment à des langages nouveaux ( nouveaux pour moi ).
    Sur le forum algorithme, Petitours a posé une question ici ; le sujet m'a intéressé, et j'ai développé une solution en Python. A priori le code ci-dessous est correct.

    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    # -*- coding:Utf-8 -*-
     
    # Enoncé de l'exercice : Forum développer.com, message posté par petitours:
    # http://www.developpez.net/forums/d1600384-2/general-developpement/algorithme-mathematiques/general-algorithmique/regroupements-d-objets-adresse/
    #
     
     
    def ff_lire_data(fic ) :
        " Lit le fichier de data,       ligne 1 = timeout,       lignes suivantes = pour chaque paquet, 2 colonnes (adesse,longueur)"
     
        nf = open(fic, 'r')
        #  Traitement des erreurs ...
        lig = nf.readline()
        xx = lig.split(',')
        timeout = int( xx[0] )
     
        ok = 1
        i = 0
        les_addd= []       # Les adresses de tous les paquets
        les_lggg = []      # et leur longueur
        lig = nf.readline()
        while ok == 1  :
            i=i+1
            xx = lig.split(',')
            les_addd.append(  int(xx[0])  )     # Adresse
            les_lggg.append(  int(xx[1])  )     # Longueur
            lig = nf.readline()       
            if lig == "" :
                print (' fin de fichier ')
                ok = 0
     
        nf.close
        return ( [ timeout , i , les_addd, les_lggg ] )         # Timeout, nbre de paquets, plus 2 tableaux addr et longueurs.
    # **********************************************************************************************************
     
     
    # **********************************************************************************************************
    def ff_calcule_cout( add_debut, add_fin, qtimeout) :
        " Calcul du coût de transmission d'un groupe de données. ---------------------------------------"
        ii1 = add_fin - add_debut +1
        ii1 = 12 + 1.04 * ( 5+ ii1 )
        ii2 = 12 + qtimeout
        if ii2 > ii1 :
            ii1 = ii2           # le max des 2 calculs. ------------------------------------------------
        return ii1
    # **********************************************************************************************************
     
     
     
    # **********************************************************************************************************
    def ff_duplique  ( tb ) :
        "Fonction pour dupliquer un tableau" 
        # petite fonction , car quand on fait   tb_svg = tb, ça ne duplique pas les données...
        # J'imagine qu'il existe une fct standard, mais je ne la connais pas, donc je la crée.
        tb2 = []
        for un in tb :
            tb2.append(un)
        return tb2
    # **********************************************************************************************************
     
     
     
     
    # **********************************************************************************************************
    def affiche_en_clair(qscenar, tb_add, tb_lg) :
        "Fonction qui va afficher en clair les endroits où il faut séparer les paquets "
        les_0_1 = qscenar[0]
        print ( "$$$$$ $$$$$ $$$$$ Syntèse scénario $$$$$ $$$$$ $$$$$")
        for i in range(len(les_0_1) ) :
            if les_0_1[i] == 1 :
                print ( " Coupure après le paquet qui débute à l'adresse ", str( tb_add[i] ) , sep = " : " )
     
        for i in range(len(les_0_1) ) :
            if les_0_1[i] == 1 :
                print (  str( tb_add[i] ) , end = " // " )
    # **********************************************************************************************************
     
     
     
     
    # Programme principal   ************************************************************************************
    # 1. Initialisation des données --------------------------------------------------------------------
    [ timeout , nb_paquets, les_addd, les_lggg ] = ff_lire_data( "c:\prj\petitours.csv" )
     
    lg_max = 250
    nb_paquets = nb_paquets+1
    les_addd.append ( 99999999)
    les_lggg.append ( 0)
        # J'ajoute un paquet bidon très loin, ainsi on va s'obliger à 'fermer' après le dernier paquet, dans la boucle générale.(pas besoin de code particulier pour la fin de tableau).
     
    tb_scenar = []
    un_scenar = ( [], les_addd[0], 0  ,0 )  #  1=liste des 0 ou 1  , 2= addresse du 1er paquet après le dernier mur,    3=Cout cumulé    4= Redondant avec 2 , valeur du dernier 0/1
    tb_scenar.append(un_scenar )
     
    # 2. Boucle sur les paquets --------------------------------------------------------------------------
    for i in range( nb_paquets-1) :
        tb_scenar2 = []
        fin_paquet_a_venir = les_addd[i+1] + les_lggg[i+1] - 1
        best_cout = 9999999999
        for un_scenar  in   tb_scenar  :
            les_0_1_svg = un_scenar[0]
            addr_prem_paquet = un_scenar[1]
            cout_cumule = un_scenar[2]
     
            #if fin_paquet_a_venir - addr_prem_paquet <= lg_max :
            for k in range ( 2) :
                # on ajoute 2 scenarios
     
                # k=0 : pas de mur après i,         k=1 : avec un mur après i
                les_0_1 = ff_duplique ( les_0_1_svg)
                les_0_1.append(k)
                if k == 0 :
                    if fin_paquet_a_venir - addr_prem_paquet <= lg_max :
                        # pas de mur après i, ossible uniquement si i+1 n'est pas trop loin.
                        un_scenar = ( les_0_1, addr_prem_paquet, cout_cumule, k )
                        tb_scenar2.append(un_scenar)
                    # Fin du test : if futur-paquet 'compatible
                else :
                    cout_incremental = ff_calcule_cout (  addr_prem_paquet , fin_paquet_a_venir , timeout )
                    nv_cout =  cout_cumule + cout_incremental
                    un_scenar = ( les_0_1, les_addd[i+1],  nv_cout , k )
                    if nv_cout < best_cout :
                        best_cout = nv_cout      # Je mémorise le coût minimal parmi les scénarios qui finnissent par un mur à cet endroit.
                    tb_scenar2.append(un_scenar)
     
            # fin de la boucle for k in 0,1
        # Fin de la boucle : Pour tous les scénarios qui étaient en attente
     
        # Suppression de tous les scénarios 'périmés'
        nj = len(tb_scenar) 
        for j in  range(nj) :
            del ( tb_scenar[0] )
     
        # Nettoyage des scenarios trop couteux,    et on re-transfère vers tb_scenar au lieu de tb_scenar2
        for un_scenar  in   tb_scenar2  :
            if un_scenar[3] == 0 :          # Les scenar  'ouverts'
                tb_scenar.append(un_scenar)
            else :                          # Les scénar fermés par un mur.
                cout_cumule = un_scenar[2]
                if cout_cumule == best_cout :
                    tb_scenar.append(un_scenar)
                    best_cout = -1         #  Je viens de copier un scénario, les autres scénarios ex-aequo ne m'intéressent plus.
     
        print ( "Fin du step i= ", str( i ), "  Nb scénar dans le tuyau = ", str( len( tb_scenar) ), "   Addr/lg du paquet à venir = ", str(les_addd[i+1]), " ; " , str ( les_lggg[i+1] ) )
     
    # Fin de la boucle sur i
    # Affichage du résultat
    for un_scenar in tb_scenar :
        affiche_en_clair ( un_scenar, les_addd, les_lggg )
    Là où je ne suis pas satisfait, c'est que j'ai l'impression d'avoir codé cela comme je l'aurais fait en VB ou je ne sais quel autre langage. Si je poste ce code ici, c'est pour avoir vos retours. Comment mieux utiliser les avantages de Python.Comment rendre ce code 'Pythonique'.
    Je ne vous demande pas de tout refaire de A à Z, ça ne m'aiderait pas, je ne comprendrais probablement rien. Mais si vous pouviez corriger tel ou tel détail, je suis preneur.

  2. #2
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    je te propose le code suivant, modifié (et néanmoins non-testé) :
    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    # -*- coding: utf-8 -*-
     
    def ff_lire_data (fic):
       """
       Lit le fichier de data
       ligne 1 = timeout
       lignes suivantes = pour chaque paquet, 2 colonnes (adesse,longueur)
       """
       with open(fic, 'r') as nf:
          timeout = nf.readline().split(',')[0]
     
          les_addd = [] # Les adresses de tous les paquets
          les_lggg = [] # et leur longueur
          for i, lig in enumerate(f):
             addr,longueur = lig.split(',')
             les_addd.append(addr)      # Adresse
             les_lggg.append(longueur)  # Longueur
          print ('fin de fichier')
       return [ timeout , i+1 , les_addd, les_lggg ]  # Timeout, nbre de paquets, plus 2 tableaux addr et longueurs.
     
    def ff_calcule_cout (add_debut, add_fin, qtimeout):
       """
       Calcul du coût de transmission d'un groupe de données.
       """
       ii1 = add_fin - add_debut + 1
       ii1 = 12 + 1.04 * ( 5 + ii1 )
       ii2 = 12 + qtimeout
       return max(ii1, ii2)
     
    ff_duplique = lambda tb: list(tb)
     
    def affiche_en_clair (qscenar, tb_add, tb_lg):
       """
       Fonction qui va afficher en clair les endroits où il faut séparer les paquets
       """
       les_0_1 = qscenar[0]
       print ("$$$$$ $$$$$ $$$$$ Syntèse scénario $$$$$ $$$$$ $$$$$")
       for i in range(len(les_0_1) ) :
          if les_0_1[i] == 1 :
             print (" Coupure après le paquet qui débute à l'adresse : {}".format(tb_add[i]))
       for i in range(len(les_0_1) ) :
          if les_0_1[i] == 1 :
             print (str(tb_add[i]), end = " // ")
     
    if __name__ == '__main__':
       [ timeout, nb_paquets, les_addd, les_lggg ] = ff_lire_data("c:\prj\petitours.csv")
     
       lg_max = 250
       nb_paquets = nb_paquets + 1
       les_addd.append (99999999)
       les_lggg.append (0)
     
       tb_scenar = [(    # initialisation directe d'une liste avec 1 seul tuple
          [],            # liste des 0 ou 1
          les_addd[0],   # addresse du 1er paquet après le dernier mur
          0,             # Cout cumulé
          0              # Redondant avec 2, valeur du dernier 0/1
       )]
     
       for i in range(1, nb_paquets):
          tb_scenar2 = []
          fin_paquet_a_venir = les_addd[i] + les_lggg[i] - 1
          best_cout = 9999999999
          for un_scenar in tb_scenar:
             les_0_1_svg, addr_prem_paquet, cout_cumule, _ = un_scenar
             for k in [0, 1]:  # tant qu'à faire...
                les_0_1 = ff_duplique(les_0_1_svg)
                les_0_1.append(k)
                if k == 0 :
                   if fin_paquet_a_venir - addr_prem_paquet <= lg_max :
                      un_scenar = (les_0_1, addr_prem_paquet, cout_cumule, k)
                      tb_scenar2.append(un_scenar)
                else :
                   cout_incremental = ff_calcule_cout (addr_prem_paquet, fin_paquet_a_venir, timeout)
                   nv_cout = cout_cumule + cout_incremental
                   un_scenar = (les_0_1, les_addd[i], nv_cout, k)
                   best_cout = min(best_cout, nv_cout)
                   tb_scenar2.append(un_scenar)
     
          del tb_scenar[:]  # empty
     
          for un_scenar in tb_scenar2:
             if un_scenar[3] == 0:
                tb_scenar.append(un_scenar)
             else :
                cout_cumule = un_scenar[2]
                if cout_cumule == best_cout :
                   tb_scenar.append(un_scenar)
                   best_cout = -1
     
          print ("Fin du step i= {}   Nb scénar dans le tuyau= {}   Addr/lg du paquet à venir= {} ; ".format(i, len(tb_scenar), les_addd[i+1], les_lggg[i+1]))
     
       for un_scenar in tb_scenar :
          affiche_en_clair (un_scenar, les_addd, les_lggg)
    il ne s'agit ici que de quelques remarques d'ordre général du point de vue de la syntaxe, nullement sur l'optimisation ou l'algorithme en lui-même étant donné que je n'ai absolument pas compris ce dont il était question dans la discussion avec petitours

    • la fonction ff_lire_data() est la plus à même d'être "pythonisée"
    • la fin du bloc with open() as marque implicitement la fermeture du fichier, that's so pythonic...
    • pour récupérer le timeout on lit la première ligne, on découpe sur la virgule et on conserve la première partie : timeout = nf.readline().split(',')[0]
    • la fonction enumerate() renvoit à la fois le numéro de la ligne (à partir de 0) et la ligne elle même, plus besoin de tenir un compteur à jour
    • on hésitera pas à utiliser les fonctions max() et min() plutot que de les déterminer à l'ancienne
    • le fonction ff_duplique() se résume à un return list(tb), s'il faut vraiment faire une fonction on peut la définir comme suit : ff_duplique = lambda tb: list(tb)
    • initialiser un_scenar pour ensuite le rajouter à la liste nouvellement créée tb_scenar n'est pas pertinent, on peut réaliser une initialisation plus directe
    • faire un for i in range(nb-1) pour ensuite utiliser partout des i+1 n'est pas très habile, on peut faire une boucle for i in range(1, nb) directement
    • s'il s'agit de vider tous les elements de tb_scenar tout en conservant son type liste, la syntaxe suivante est plus directe : del tb_scenar[:] ou encore tb_scenar[:] = []
      il semble qu'avec python >= 3.3 la syntaxe tb_scenar.clear() marche aussi
    • l'utilisation de format() dans les chaines à afficher permet de rendre les print() moins longs et plus clairs
    • pour tout le reste il y a PEP8

  3. #3
    Membre émérite
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2013
    Messages
    485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 485
    Par défaut
    J'ai commencé à regarder ce code et j'ai vite arrêté en faite.
    Bravo à BufferBob qui a eu se courage.

    Alors ma remarque n'est pas du tout sur le "pythonique" mais sur des bonnes partiques de codage.
    Je te rassure, tu n'es pas le seul à avoir ces mauvaises habitudes et tu n'es pas le dernier à qui je fais ces remarques sur ce forum.

    Je m'explique.
    Est-il nécessaire de chercher a nommer les variables avec un nom le plus abstrait possible pour maximiser le risque de ne pas comprendre à quoi elle correspond ?

    En gros, peux-tu, rapidement, sans relire ton code, me donner le rôle et le sens exacte de :
    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
    i
    ii1
    ii2
    j
    k
    les_0_1
    les_addd
    les_lggg
    lg_max
    lig
    nf
    nj
    ok
    tb2
    tb_scenar
    tb_scenar2
    un
    un_scenar
    xx
    Pour information, la taille des noms de variables en python n'est pas limité, la norme PEP8 recommande un maximum de 79 caractères
    Donc, ne pas hésiter à avoir des noms bien explicite.
    Personnellement, je bannis tout les noms de moins de 4 caractères.
    Cela évite non seulement de rajouter un roman de commentaire et en plus cela réduit de la crispation des personnes qui vous relisent.

    Je recommande d'avoir cette adage dans la tête quand on développe du code:
    Développer en imaginant que la personne qui va maintenir votre code est un psychopathe meurtrier qui connait votre adresse .

  4. #4
    Membre confirmé
    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
    Par défaut
    Citation Envoyé par Laurent 1973 Voir le message

    Pour information, la taille des noms de variables en python n'est pas limité, la norme PEP8 recommande un maximum de 79 caractères

    :
    Je chipote, mais je suis d'accord avec toi sur le fait que les noms des variables sont importants. Par contre, 79 c'est la taille maximum d'une ligne d'après PEP8

  5. #5
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 215
    Par défaut
    Merci pour vos retours, spécialement BufferBob. Je vais regarder tout cela ce soir et probablement revenir vers vous.

    A Laurent, sans regarde mon code, voici des explications sur mes noms de variables :
    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
     
    i                itérateur
    ii1 ii2          je ne sais plus , probablement des itérateurs, mais forcément ces 2 variables jouent des rôles symétriques...
    j                 itérateur
    k                itérateur , compteur ?
    les_0_1       tableau de booléens , central dans mon algorithme 
    les_addd     tableau donnant les adresses des paquets à traiter
    les_lggg      tableau donnant les Longueurs des paquets à traiter   ( idéalement, j'aurais dû faire une structure avec (adresse+longueur), puis un tableau avec cette structure.
    lg_max       longueur Max d'une succession de paquet ( En fait, c'est une constante égale à 250 )
    lig              Dans la procédure de lecture de fichier, c'est une ligne de ce fichier
    nf               nf comme n° de fichier   ( open nf, read nf, close nf)      
    nj               Un nombre ( probablement je vais avoir une iteration for j in range ( nj)  ?  )  
    ok              Un Booléen, probablement pour gérer une boucle 'infinie'
    tb2             Certainement un tableau temporaire.
    tb_scenar    un tableau avec tous les Scénarios à traiter
    tb_scenar2   Idem tb_scenar ... Je copie tb_scenar dans tb_scenar2, puis tb_scenar2 dans tb_scenar
    un               itérateur dans une petite procédure qui ne devrait pas exister, (BufferBob m'a donné la syntaxe pour supprimer cette procédure) , j'itère   for un in tableau  
    un_scenar     Structure de Base, qui représente un scénario. (suite de booléens les_0_1, pour savoir où on découpe, puis coût_cumulé de ce scénario ... )
    xx                ?  Une variable temporaire, certainement créée /initialisée sur une ligne, et relue sur la ligne suivante. puis utilisée nulle part ailleurs dans le code.
    Alors, effectivement, certains de ces noms peuvent être abstraits. Mais par exemple LIG ou NF, dans tous les programmes que je fais, j'utilise cette notation NF pour ouvrir/lire/fermer un fichier, et LIG pour lire un fichier. Ces 2 noms de variables sont donc très concrets pour moi et pour les gens qui travaillent avec moi.

    Mais j'ai bien noté la proposition 'pythonique' de BufferBob :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Remplacer :
     
    lig = nf.readline()
    timeout =  lig.split(',')[0]
     
    par :
     
    timeout = nf.readline().split(',')[0]
    (à aménager, car j'ai besoin de convertir timeout en entier au lieu de string)

  6. #6
    Membre émérite
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2013
    Messages
    485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 485
    Par défaut
    Citation Envoyé par tbc92 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    i                itérateur
    ii1 ii2          je ne sais plus , probablement des itérateurs, mais forcément ces 2 variables jouent des rôles symétriques...
    j                 itérateur
    k                itérateur , compteur ?
    Mais itérateur de quoi? de patate ou de carotte ? toi-même tu de sais pas de quoi justement.
    C'est une (mauvaise) habitude que des développeurs ont d'utiliser ces lettres (i,j,k,l,...) dans des boucles.
    Au résultat, après quelques des boucles imbriquées ou refactoring, on se mélange allégrement entre les indices qui ne veulent absolument rien dire à part "je suis un itérateur".
    Est-ce si difficile de les remplacer par "patate_iter" et "carotte_iter" ?
    Je ne reviendrais pas sur tes autres variables qui pourrait, dans la même idée, être plus explicite dans leur notation.

    Citation Envoyé par tbc92 Voir le message
    ...
    Ces 2 noms de variables sont donc très concrets pour moi et pour les gens qui travaillent avec moi.
    ...
    Vu que l'on est pas habitué à travailler ensemble, nous ne partageons pas la même norme de codage et d'où ma réticente à me plonger dans ton code.
    Or, là justement, tu demandes à des gens non habitué à travailler avec toi de commenter ton code ... afin de savoir s'il colle a de bonnes "règles" de Python.

    Mes remarques ne sont pas contre toi, tbc92: tu ne suit qu'une habitude du monde de l'informatique.
    C'est malheureusement trop fréquent que des équipes logiciels ne cherchent pas à améliorer la lisibilité du code pour quelqu'un qui n'est pas de sa "tribu".

    Je me permet de t'en faire part d'autant plus qu'entant qu'ingénieur qualité, tu dois être très sensibilisé à améliorer les processus de travail dans l'optique de pérennisation.

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

Discussions similaires

  1. [Dates] Le résultat de mon code est inexact
    Par bebas dans le forum Langage
    Réponses: 1
    Dernier message: 27/02/2007, 10h50
  2. Réponses: 1
    Dernier message: 08/02/2007, 09h11
  3. Pourquoi mon code est plus lent que Arrays.sort
    Par alexis779 dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 12/12/2006, 12h44
  4. [Tableaux] Mon code est bon ?
    Par garaut dans le forum Langage
    Réponses: 8
    Dernier message: 14/11/2006, 15h47
  5. [Dates] calcul de date est ce que mon code est bon?
    Par carmen256 dans le forum Langage
    Réponses: 2
    Dernier message: 09/06/2006, 11h30

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