Python: La compréhension de listes, effectuer des opérations complexes

Voici un exemple, qui ne sert pas à grand chose, mais qui permet de montrer les différents calculs complexes qu'il est possible de faire avec la compréhension de liste.

Dans cet exemple, j'ai une classe qui permet de générer, aléatoirement, des codes EAN13.

>>> from random import randint
>>> class EAN13():
    GENERATES = []
    def __init__(self):
        pass
    def new(self, count=1):
        ct = count
        while ct > 0:
            ean13 = '{:03}{}'.format(randint(40, 49), ''.join([((x+4)*'0'+str(randint(1, int((x+4)*'9'))))[-(x+4):] for x in range(2)]))
            ean13 += str(10 - (sum([int(y) * 3 if x % 2 == 0 else int(y) for x, y in enumerate(list(ean13), start=1)]) % 10))[-1]
            if ean13 not in EAN13.GENERATES:
                EAN13.GENERATES.append(ean13)
                ct -= 1
        return EAN13.GENERATES[-count:]

>>> EAN13().new(count=20)
['0467764013590', '0442457715586', '0478050754264', '0498544873950', '0419792606732', '0436177825380', '0487308428246', '0449011102394', '0487403914866', '0462030759684', '0438507088359', '0405068027851', '0489779856153', '0437057321695', '0465499916742', '0467772469648', '0493671951373', '0483943989975', '0499830229161', '0462787735498']

Comme indiqué sur wikipédia:

Un code EAN13 est composé de 13 chiffres

  • les deux ou trois premiers correspondent au pays de provenance du produit, ou à une classe normalisée de produits ;
  • les 4 ou 5 suivants sont le numéro de membre de l’entreprise participant au système EAN ;
  • les 4 ou 5 suivants sont le numéro d’article du produit ainsi marqué et
  • le treizième est une clé de contrôle calculée en fonction des douze précédents.

Je vais "exploser" mon code pour expliquer les différentes étapes.

Voici la ligne qui permet de générer aléatoirement les 12 premiers chiffres:

>>> ean13 = '{:03}{}'.format(randint(40, 49), ''.join([((x+4)*'0'+str(randint(1, int((x+4)*'9'))))[-(x+4):] for x in range(2)]))

Les 3 premiers chiffres de mon code, ceux correspondant au pays de provenance du produit, ou à une classe normalisée de produits, est un nombre aléatoire allant de 040 à 049 (à l'aide la fonction randint et format)

>>> '{:03}{}'.format(randint(40, 49), '')
'041'

Voici la fameuse compréhension de liste qui va permettre de générer deux nombres.
Le premier composé de 4 chiffres et le second composé de 5 chiffres.

>>> [((x+4)*'0'+str(randint(1, int((x+4)*'9'))))[-(x+4):] for x in range(2)]
['2983', '23696']

Si nous faisions la même chose mais sans utiliser la compréhension de liste, ça donnerait ceci:

>>> L = []
>>> for x in range(2):
    L.append(((x+4)*'0'+str(randint(1, int((x+4)*'9'))))[-(x+4):])
   
>>> L
['5237', '92948']

J'utilise donc ma boucle for pour gérérer la première fois (x=0) un nombre de 4 chiffres et la fois suivante (x=1) un nombre de 5 chiffres.

J'utilise également le slicing ([-(x+4):]) pour conserver uniquement les x derniers chiffres de mes deux nombres aléatoires auquels j'ai ajoutés des '0' à gauche pour être certain d'avoir le bon nombre de chiffres.

J'aurais également pû utiliser la fonction format comme ceci:

>>> L.append('{0:0{1}}'.format(randint(1, int((x+4)*'9')), x+4))

Il ne reste plus qu'à calculer la clé qui sera donc le treizième et dernier chiffre de notre code.

Voici donc la ligne de code qui permet de le faire:

>>> ean13 += str(10 - (sum([int(y) * 3 if x % 2 == 0 else int(y) for x, y in enumerate(list(ean13), start=1)]) % 10))[-1]

Cette ligne de code utilise également la compréhension de liste.

J'utilise donc une boucle for et la fonction enumerate qui permet d'indexer chaque chiffres de mon code.

Je vais donc pouvoir faire la somme de tous mes chiffres et en ayant multiplié par 3 les rangs pairs (comme indiqué dans la formule de calcul de la clé).

>>> list(ean13)
['0', '4', '6', '5', '0', '3', '9', '9', '9', '0', '9', '9']
>>> [int(y) * 3 if x % 2 == 0 else int(y) for x, y in enumerate(list(ean13), start=1)]
[0, 12, 6, 15, 0, 9, 9, 27, 9, 0, 9, 27]
>>> sum([int(y) * 3 if x % 2 == 0 else int(y) for x, y in enumerate(list(ean13), start=1)])
123

Ci-dessous le reste du code détaillé ligne par ligne pour obtenir la clé finale (le caractère '_' représentant le résultat de la dernière exécution)

>>> _ % 10
3
>>> 10 - _
7
>>> str(_)[-1]
'7'

Pour info:
La première ligne permet d'obtenir le reste de la division par 10 (123%10=3)
La seconde ligne permet de soustraire à 10 le chiffre précédement obtenu.
La troisième ligne permet uniquement de garder le bon chiffre, dans le cas où le reste de la division est égal à 0.

La compréhension de list en Python est vraiment très puissante.
Elle permet de faire beaucoup de choses d'une manière plus concentrée et parfois plus facile à comprendre.

J'espère avoir été assez clair dans mes explications...

Ajouter un commentaire

Filtered HTML

  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Tags HTML autorisés : <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Les lignes et les paragraphes vont à la ligne automatiquement.

Plain text

  • Aucune balise HTML autorisée.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
CAPTCHA
Cette question permet de s'assurer que vous êtes un utilisateur humain et non un logiciel automatisé de pollupostage.
CAPTCHA visuel
Entrez les caractères (sans espace) affichés dans l'image.