TP 1
TP 1
TP 1
Le caractère d’espacement est ignoré à l’intérieur des parenthèses et des crochets, ce qui est parfois
utile pour les longues formules :
long_winded_computation = (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 +
15 + 16 + 17 + 18 + 19 + 20)
Vous pouvez aussi utiliser une barre oblique inverse pour indiquer qu’une instruction continue sur la
ligne suivante, mais c’est rare :
two_plus_three = 2 + \
3
Une des conséquences de l’utilisation du caractère d’espacement pour la mise en page est la
difficulté d’effectuer des copier-coller de code dans le shell Python. Par exemple, si vous essayez de
copier, dans le shell Python ordinaire, le code :
for i in [1, 2, 3, 4, 5]:
Les arguments d’une fonction peuvent aussi recevoir des valeurs par défaut, vous spécifiez alors
explicitement les arguments uniquement quand vous voulez leur donner une valeur différente de
celle par défaut :
def my_print(message="my default message"):
print (message)
my_print("hello") # imprime 'hello'
my_print() # imprime 'my default message'(mes messages par défaut)
Python utilise la barre oblique inverse pour coder les caractères spéciaux. Par exemple :
tab_string = "\t" # représente le caractère de tabulation
len(tab_string) # vaut 1
Si vous avez besoin d’une barre oblique inverse comme caractère (par exemple, pour nommer un
répertoire sous Windows ou dans une expression rationnelle), vous devez créer des chaînes de
caractères brutes (raw en anglais) à l’aide de r"" :
not_tab_string = r"\t" # représente les caractères '\' et 't'
len(not_tab_string) # vaut 2
Vous pouvez créer des chaînes de caractères sur plusieurs lignes à l’aide de triples [doubles]
guillemets :
multi_line_string = """Ceci est la première ligne.
Et ceci est la deuxième ligne
Et ceci est la troisième ligne"""
Vous pouvez aussi utiliser des crochets pour « découper » des listes :
first_three = x[:3] # [-1, 1, 2]
three_to_end = x[3:] # [3, 4, ..., 9]
one_to_four = x[1:5] # [1, 2, 3, 4]
last_three = x[-3:] # [7, 8, 9]
without_first_and_last = x[1:-1] # [1, 2, ..., 8]
copy_of_x = x[:] # [-1, 1, 2, ..., 9]
Python dispose par ailleurs d’un opérateur pour vérifier l’appartenance d’un élément à une liste :
1 in [1, 2, 3] # Vrai (True)
0 in [1, 2, 3] # Faux (False)
Et souvent, il est pratique de déballer des listes (unpack en anglais) en assignant chaque élément à
une variable si vous savez combien d’éléments la liste contient :
x, y = [1, 2] # maintenant x vaut 1, y vaut 2
Il est d’usage de marquer d’un tiret bas une valeur dont vous allez vous débarrasser :
_, y = [1, 2] # maintenant y == 2, peu importe le premier élément
Les tuples sont un moyen pratique pour retourner des valeurs multiples depuis des fonctions :
def sum_and_product(x, y):
return (x + y),(x * y)
Les tuples (et les listes) peuvent aussi s’utiliser pour des assignations multiples :
x, y = 1, 2 # maintenant x vaut 1, y vaut 2
x, y = y, x # manière pythonique de changer les variables ; maintenant x vaut 2, y vaut
1
Mais vous déclencherez une erreur KeyError si vous demandez une clé qui n’est pas dans le
dictionnaire :
try:
kates_grade = grades["Kate"]
except KeyError:
print("no grade for Kate!")
Les dictionnaires possèdent une méthode get qui retourne une valeur par défaut (au lieu de
déclencher une exception) quand vous cherchez une clé qui n’est pas dans le dictionnaire :
joels_grade = grades.get("Joel", 0) # égale 80
kates_grade = grades.get("Kate", 0) # égale 0
no_ones_grade = grades.get("No One") # par défaut vaut None
On utilisera souvent les dictionnaires pour représenter de manière simple des données structurées :
tweet = {
"user" : "joelgrus",
"text" : "Data Science is Awesome", "retweet_count" : 100,
"hashtags" : ["#data", "#science", "#datascience", "#awesome", "#yolo"]
}
En plus de pouvoir chercher une clé spécifique, on peut les balayer toutes :
tweet_keys = tweet.keys() # liste de clés
tweet_values = tweet.values() # liste de valeurs
tweet_items = tweet.items() # liste de tuples(clé-valeur)
"user" in tweet_keys # Vrai mais lent (in dans une liste)
"user" in tweet # plus pythonique, utilise la version dict du in
"joelgrus" in tweet_values # Vrai
Les clés de dictionnaires doivent être immutables ; en particulier, on ne peut pas utiliser des listes
comme clés. Si vous avez besoin d’une clé correspondant à plusieurs éléments, il faut utiliser un tuple
ou imaginer une manière de transformer la clé en une chaîne de caractères.
Vous pouvez aussi utiliser la tactique « mieux vaut s’excuser après coup plutôt que demander la
permission avant » et vous contenter de gérer l’exception quand vous cherchez une clé manquante :
word_counts = {}
for word in document:
try:
word_counts[word] += 1
except KeyError:
word_counts[word] = 1
Une troisième méthode consiste à utiliser get, qui gère en douceur le cas des clés manquantes :
word_counts = {}
for word in document:
previous_count = word_counts.get(word, 0)
word_counts[word] = previous_count + 1
Chacune de ces méthodes est assez peu pratique, ce qui explique pourquoi defaultdict existe. Un
defaultdict est comme un dictionnaire normal à la différence que, quand vous cherchez une valeur
qu’il ne contient pas, il ajoute d’abord une valeur pour cette clé à l’aide d’une fonction sans
argument que vous avez fournie lors de sa création. Pour utiliser des defaultdict, il faut les importer
depuis le module collections :
from collections import defaultdict
word_counts = defaultdict(int) # int() produit 0
for word in document:
word_counts[word] += 1
Les defaultdict sont également très utiles initialisés avec list ou dict ou même avec vos propres
fonctions :
dd_list = defaultdict(list) # list() produit une liste vide
dd_list[2].append(1) # maintenant dd_list contient {2: [1]}
dd_dict = defaultdict(dict) # dict() produit un dict vide
dd_dict["Joel"]["City"] = "Seattle" # { "Joel" : { "City" : Seattle"}}
1.11 LES COMPTEURS
Un compteur (Counter) transforme une séquence de valeurs en un objet de style defaultdict(int) qui
fait correspondre des clés à des compteurs. Nous l’utiliserons avant tout pour créer des
histogrammes :
from collections import Counter
c = Counter([0, 1, 2, 0]) # c vaut (à la base) { 0 : 2, 1 : 1, 2 : 1 }
Nous utiliserons des ensembles principalement pour deux raisons. La première est que le in est une
opération très rapide sur les ensembles. Si nous avons une grande collection d’éléments que nous
voulons utiliser pour faire un test d’appartenance, un ensemble est mieux adapté qu’une liste :
stopwords_list = ["a","an","at"] + hundreds_of_other_words + ["yet", "you"]
"zip" in stopwords_list # Faux, mais il faut tester chaque élément
stopwords_set = set(stopwords_list)
"zip" in stopwords_set # très rapide à vérifier
La seconde raison est qu’on trouve ainsi les éléments distincts d’une collection :
item_list = [1, 2, 3, 1, 2, 3]
num_items = len(item_list) # 6
item_set = set(item_list) # {1, 2, 3}
num_distinct_items = len(item_set) # 3
distinct_item_list = list(item_set) # [1, 2, 3]
Si vous avez besoin d’utiliser des logiques plus complexes, vous pouvez faire appel à continue et
break :
for x in range(10):
if x == 3:
continue # va immédiatement à l’itération suivante
if x == 5:
break # quitte définitivement la boucle
print (x)
Ce code va afficher 0, 1, 2 et 4.
1.14 VRAI/FAUX
En Python, les booléens fonctionnent comme dans la plupart des langages à l’exception près qu’ils
sont représentés avec une majuscule :
one_is_less_than_two = 1 < 2 # égale vrai
true_equals_false = True == False # égale faux
Python utilise la valeur None pour indiquer une valeur qui n’existe pas. C’est l’équivalent de null dans
d’autres langages :
x = None
print (x == None) # imprime True, mais n’est pas pythonique
print (x is None) # imprime True, et est pythonique
Python vous permet d’utiliser n’importe quelle valeur quand il attend un booléen. Les termes
suivants sont tous considérés comme False (faux) :
False
None
[] (une liste vide)
{} (un dictionnaire vide)
""
set()
0
0.0
Presque tout le reste est considéré comme True (vrai). Il est donc facile d’utiliser des instructions
conditionnelles avec if pour tester si des listes, des chaînes de caractères ou des dictionnaires sont
vides. Cela peut aussi parfois induire des bugs difficiles à résoudre si vous n’avez pas ce
comportement bien à l’esprit :
s = some_function_that_returns_a_string()
if s:
first_char = s[0]
else:
first_char = ""
car and retourne sa deuxième valeur quand la première est « vraie », la première quand elle ne l’est
pas. De la même façon, si x est un nombre ou éventuellement None :
safe_x = x or 0
Python possède une fonction all qui prend en entrée une liste et retourne True si chaque élément est
vrai et une fonction any qui retourne True si au moins un des éléments est vrai :
all([True, 1, { 3 }]) # Vrai
all([True, 1, {}]) # Faux, {} est plutôt faux
any([True, 1, {}]) # Vrai, True est plutôt vrai
all([]) # Vrai, pas d’éléments plutôt faux dans la liste
any([]) # Faux, pas d’éléments plutôt vrais dans la liste
1.15 TRIER
Toute liste Python possède une méthode de tri (sort) pour la trier sur place. Si vous ne voulez pas
modifier votre liste, vous pouvez utiliser la fonction sorted, qui retourne une nouvelle liste :
x = [4,1,2,3]
y = sorted(x) # vaut [1,2,3,4], x est inchangé
x.sort() # maintenant x vaut [1,2,3,4]
Par défaut, sort (et sorted) trient une liste du plus petit au plus grand par comparaison naïve des
éléments entre eux.
Si vous voulez trier du plus grand au plus petit, spécifiez le paramètre reverse=True. Au lieu de
comparer les éléments eux-mêmes, vous pouvez comparer les résultats d’une fonction que vous
indiquerez avec la clé :
# trie la liste selon la valeur absolue de la plus grande à la plus petite
x = sorted([-4,1,-2,3], key=abs, reverse=True) # is [-4,3,-2,1]
# trie les mots et les compteurs du nombre le plus élévé au plus bas
wc = sorted(word_counts.items(),
key=lambda (word, count): count,
reverse=True)
Imaginons que vous ne disposez pas de set dans Python. Nous voudrions alors créer notre propre
classe Set.
Quel devrait être le comportement de notre classe ? Soit une instance donnée de Set ; nous devons
être capables d’y ajouter des éléments, de retirer des éléments et de vérifier s’il contient une
certaine valeur. Pour cela, nous allons créer des fonctions membres, ce qui veut dire que nous y
accéderons en utilisant une instance d’objet Set suivie d’un point :
# par convention, on attribue aux classes de noms en PascalCase
class Set:
# voici les fonctions membres
# chacune admet un paramètre "self" (une autre convention)
# qui fait référence à l’objet Set particulier en cours d’utilisation
def __init__(self, values=None):
"""Ceci est le constructeur.
Il est appelé quand vous créez un nouveau set.
Voilà comment l’utiliser"""
s1 = Set() # set vide
s2 = Set([1,2,2,3]) # initialise avec les valeurs
self.dict = {} # chaque instance de set a sa propre propriété dict
# qui est celle utilisée pour suivre l’appartenance
if values is not None:
for value in values:
self.add(value)
def __repr__(self):
"""ceci est la représentation d’un objet set comme chaîne de caractères
si vous la tapez dans le prompt Python ou si vous la passez à str()"""
return "Set: " + str(self.dict.keys())
# nous représenterons l’appartenance comme une clé dans self.dict avec la valeur True
def add(self, value):
self.dict[value] = True
# la valeur est dans le Set si c’est une clé du dictionnaire
def contains(self, value):
return value in self.dict
def remove(self, value):
del self.dict[value]