Modules Python : collections, time, random, os et sys

Module collections

En complément des types de données natifs (dict, list, set, tuple), le module collections propose plusieurs types supplémentaires :

  • namedtuple : génère un tuple dont les éléments sont accessibles par un nom
  • deque : file doublement terminée, permettant des ajouts et retraits rapides aux deux extrémités
  • OrderedDict : dictionnaire qui conserve l’ordre d’insertion des clés
  • defaultdict : dictoinnaire avec une valeur par défaut pour les clés manquantes
  • Counter : compteur servant à dénombrer les occurrences d’éléments

namedtuple

Un tuple classique peut représenter un ensemble immuable, par exemple les coordonnées d’un point :

>>> t = (1, 2)

Cependant, lire (1, 2) ne permet pas de comprendre qu’il s’agit d’un point. namedtuple vient résoudre ce problème :

In [1]: from collections import namedtuple

In [2]: Point = namedtuple('Point', ['x', 'y'])

In [3]: p = Point(1, 2)

In [4]: p
Out[4]: Point(x=1, y=2)

In [5]: p.x
Out[5]: 1

In [6]: p.y
Out[6]: 2

De même, pour représenter un cercle avec son centre et son rayon :

# namedtuple('Nom', [liste d'attributs])
Cercle = namedtuple('Cercle', ['x', 'y', 'r'])

Cette structure est également utile dans un jeu de cartes, où chaque carte est définie par sa couleur et sa valeur.

deque

L’accès par indice est rapide avec une list, mais les insertions et suppressions sont lentes car le stockage est linéaire. deque est optimisé pour ces opérations et cnovient parfaitement aux files et aux piles :

from collections import deque

d = deque()
d.append('a')        # ajout à droite
d.appendleft('b')    # ajout à gauche
print(d)             # deque(['b', 'a'])
d.pop()              # retire 'a'
d.popleft()          # retire 'b'

OrderedDict

Avec un dictionnaire classique, l’ordre des clés n’est pas garanti. OrderedDict conserve l’ordre d’insertion :

In [29]: from collections import OrderedDict

In [30]: d = dict([('a', 1), ('b', 2), ('c', 3)])

In [31]: d
Out[31]: {'a': 1, 'b': 2, 'c': 3}         # ordre quelconque

In [32]: od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])

In [33]: od
Out[33]: OrderedDict([('a', 1), ('b', 2), ('c', 3)])   # ordre préservé

Attention : l’ordre est celui de l’insertion, et non celui des clés elles-mêmes :

In [35]: od['z'] = 1
In [36]: od['y'] = 2
In [37]: od['x'] = 3

In [38]: od.keys()
Out[38]: odict_keys(['a', 'b', 'c', 'z', 'y', 'x'])

defaultdict

Supposons une liste de valeurs [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]. On souhaite placer les valeurs supérieures à 66 dans une clé 'k1' et les valeurs inférieures à 66 dans 'k2'. Avec un dictionnaire standard :

valeurs = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
mon_dico = {}

for v in valeurs:
    if v > 60:
        if 'k1' in mon_dico:
            mon_dico['k1'].append(v)
        else:
            mon_dico['k1'] = [v]
    elif v < 60:
        if 'k2' in mon_dico:
            mon_dico['k2'].append(v)
        else:
            mon_dico['k2'] = [v]

print(mon_dico)

Avec defaultdict, le code devient plus simple :

from collections import defaultdict

valeurs = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
mon_dico = defaultdict(list)

for v in valeurs:
    if v > 60:
        mon_dico['k1'].append(v)
    elif v < 60:
        mon_dico['k2'].append(v)

print(mon_dico)
# defaultdict(<class 'list'>, {'k1': [66, 77, 88, 99, 90], 'k2': [11, 22, 33, 44, 55]})

Pour définir une valeur par défaut qui n’est pas un type (ex. une constante), on utilise une lambda :

In [39]: from collections import defaultdict

In [40]: dd = defaultdict(lambda: 'N/A')

In [41]: dd['key1'] = 'abc'

In [43]: dd['key1']
Out[43]: 'abc'

In [44]: dd['key2']        # clé inexistante
Out[44]: 'N/A'

Counter

Counter permet de compter les occurrences d’éléments dans un itérable :

In [45]: from collections import Counter

In [46]: c = Counter('adfasdfawrsadfadfasdfzcv')

In [47]: print(c)
Counter({'a': 6, 'f': 5, 'd': 5, 's': 3, 'w': 1, 'c': 1, 'v': 1, 'r': 1, 'z': 1})

In [48]: print(c['a'])
6

Module time

Pour toutes les opérations temporelles, on importe le module time.

# Méthodes courantes
1. time.sleep(secs)      # suspend l'exécution pendant secs secondes
2. time.time()           # retourne le timestamp actuel (secondes depuis 1970-01-01)

En Python, le temps se représente sous trois formes :

  • Timestamp : nombre de secondes écoulées depuis le 1er janvier 1970.
  • Chaîne formatée : par exemple '1990-12-06'.
  • Struct_time : tuple de 9 éléments (année, mois, jour, heure, minute, seconde, jour de la semaine, jour dans l’année, heure d’été).

Symboles de formatage courants :

%y   année sur 2 chiffres (00-99)
%Y   année sur 4 chiffres (0000-9999)
%m   mois (01-12)
%d   jour du mois (01-31)
%H   heure en format 24h (00-23)
%I   heure en format 12h (01-12)
%M   minutes (00-59)
%S   secondes (00-59)
%a   nom abrégé du jour de la semaine
%A   nom complet du jour
%b   mois abrégé
%B   mois complet
%c   date et heure locales
%j   jour dans l’année (001-366)
%p   AM/PM
%U   numéro de semaine (dimanche premier jour) (00-53)
%w   jour de la semaine (0=dimanche, 6=samedi)
%W   numéro de semaine (lundi premier jour) (00-53)
%x   date locale
%X   heure locale
%Z   fuseau horaire
%%   le caractère %

Exemples des trois formats

In [49]: import time

In [50]: time.time()
Out[50]: 1539398412.6536071   # timestamp

In [51]: time.strftime('%Y%m%d %X')
Out[51]: '20181013 10:40:40'  # chaîne formatée

In [52]: time.localtime()
Out[52]: time.struct_time(tm_year=2018, tm_mon=10, tm_mday=13, tm_hour=10, tm_min=40, tm_sec=47, ...)

Conversions entre formats

Timestamp → struct_time :

In [6]: time.localtime(1500000000)
Out[6]: time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, ...)

struct_time → timestamp :

In [7]: time.mktime(time.localtime(1500000000))
Out[7]: 1500000000.0

struct_time → chaîne formatée :

In [12]: time.strftime('%Y%m%d %H:%M:%S', time.localtime(1500000000))
Out[12]: '20170714 10:40:00'

Chaîne formatée → struct_time :

In [14]: time.strptime('20170714 10:40:00', '%Y%m%d %H:%M:%S')
Out[14]: time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, ...)

Autres raccourcis :

In [16]: time.asctime(time.localtime(1500000000))
Out[16]: 'Fri Jul 14 10:40:00 2017'

In [17]: time.ctime(1500000000)
Out[17]: 'Fri Jul 14 10:40:00 2017'

Exercice

Calculer le temps écoulé depuis le 1er janvier 2008 00:00:00 jusqu’à maintenant :

import time

debut = time.strptime('2008-1-1 00:00:00', '%Y-%m-%d %H:%M:%S')
maintenant = time.localtime(time.time())
print('Depuis 2008 : %d ans %d mois %d jours %d heures %d minutes %d secondes' % (
    maintenant.tm_year - debut.tm_year,
    maintenant.tm_mon - debut.tm_mon,
    maintenant.tm_mday - debut.tm_mday,
    maintenant.tm_hour - debut.tm_hour,
    maintenant.tm_min - debut.tm_min,
    maintenant.tm_sec - debut.tm_sec
))

Module random

# Nombres à virgule flottante aléatoires
random.random()               # entre 0.0 et 1.0
random.uniform(1, 3)          # entre 1 et 3

# Nombres entiers aléatoires
random.randint(1, 5)          # entier compris entre 1 et 5 inclus
random.randrange(1, 10, 2)    # entier impair entre 1 et 9

# Sélection aléatoire
random.choice([1, '23', [4,5]])          # un élément au hasard
random.sample([1, '23', [4,5]], 2)       # deux éléments distincts

# Mélange d'une liste
item = [1, 3, 5, 7, 9]
random.shuffle(item)                     # mélange sur place
print(item)

Exercice : génération de code de vérification

import random

def generer_code(longueur=5):
    code = ''
    for _ in range(longueur):
        chiffre = random.randint(0, 9)
        lettre = chr(random.randint(65, 90))   # lettre majuscule
        caractere = random.choice([chiffre, lettre])
        code += str(caractere)
    return code

print(generer_code())

Module os (interface avec le système d’exploitation)

os.makedirs('repertoire1/repertoire2')   # création récursive
os.removedirs('repertoire1')              # suppression récursive des répertoires vides

os.mkdir('repertoire')                    # création d’un seul répertoire
os.rmdir('repertoire')                    # suppression d’un répertoire vide

os.listdir('chemin')                      # liste des fichiers et dossiers
os.remove('fichier')                      # suppression d’un fichier
os.rename('ancien', 'nouveau')           # renommage

os.stat('chemin/fichier')                 # informations sur le fichier

os.system('commande shell')              # exécution d’une commande (affichage direct)
os.popen('commande').read()              # exécution et récupération du résultat

os.getcwd()                               # répertoire de travail courant
os.chdir('autre_repertoire')              # changement de répertoire

# Sous-module os.path
os.path.abspath('chemin')                 # chemin absolu normalisé
os.path.split('chemin')                   # (répertoire, fichier)
os.path.dirname('chemin')                 # répertoire
os.path.basename('chemin')                # nom du fichier
os.path.exists('chemin')                  # True si le chemin existe
os.path.isabs('chemin')                   # True si chemin absolu
os.path.isfile('chemin')                  # True si fichier existant
os.path.isdir('chemin')                   # True si dossier existant
os.path.join('rep1', 'rep2', 'fichier')   # assemblage de chemins
os.path.getatime('chemin')                # dernier accès
os.path.getmtime('chemin')                # dernière modification
os.path.getsize('chemin')                 # taille en octets

Attributs supplémentaires :

os.sep         # séparateur de chemin ('\\' sous Windows, '/' sous Linux)
os.linesep     # fin de ligne ('\r\n' sous Windows, '\n' sous Linux)
os.pathsep     # séparateur de chemins (';' Windows, ':' Linux)
os.name        # nom du système ('nt' pour Windows, 'posix' pour Linux)

Module sys (interaction avec l’interpréteur Python)

sys.argv              # liste des arguments de la ligne de commande (premier = nom du script)
sys.exit(n)           # quitte le programme (0 = succès, autre = erreur)
sys.version           # version de l’interpréteur
sys.path              # liste des chemins de recherche des modules
sys.platform          # nom de la plateforme (ex : 'win32', 'linux')

Étiquettes: Python collections namedtuple deque OrderedDict

Publié le 8 juillet à 03h51