Au programme :
Avec des liens !
Python :
python mon_script.py
python
mthh@mthh:~$ python3
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print('Hello!')
Hello!
>>> 38
38
>>> exit()
mthh@mthh:~$ R
R version 3.4.4 (2018-03-15) -- "Someone to Lean On"
Copyright (C) 2018 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)
R est un logiciel libre livré sans AUCUNE GARANTIE.
Vous pouvez le redistribuer sous certaines conditions.
Tapez 'license()' ou 'licence()' pour plus de détails.
R est un projet collaboratif avec de nombreux contributeurs.
Tapez 'contributors()' pour plus d'information et
'citation()' pour la façon de le citer dans les publications.
Tapez 'demo()' pour des démonstrations, 'help()' pour l'aide
en ligne ou 'help.start()' pour obtenir l'aide au format HTML.
Tapez 'q()' pour quitter R.
[Sauvegarde de la session précédente restaurée]
> print('Hello!')
[1] "Hello!"
> q('no')
mthh@mthh:~$ ipython3
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: print('Hello!')
Hello!
In [2]: 12
Out[2]: 12
In [3]: exit()
a = 12
print(a, '\n', type(a))
12 <class 'int'>
a = 12.3
print(a, '\n', type(a))
print(a.is_integer())
12.3 <class 'float'> False
a = True
b = not a
print(b, '\n', type(b))
False <class 'bool'>
Les listes en Python peuvent contenir des objets hétérogènes.
a = []
a.append(1)
a.append("yo")
a.append([1, 2, 3])
a.append(4)
a.append(23.9)
a.append("Une autre chaine de caractères")
a
[1, 'yo', [1, 2, 3], 4, 23.9, 'Une autre chaine de caractères']
On va utiliser les crochets pour indexer les éléments de la listes (en Python on commence à compter à 0)
a[0] # <- Le premier élément de la liste
a[2] # <- Le troisième
# Il existe des méthodes pour enlever le dernier élément
# ou un élément particulier, etc.
a.pop()
1
[1, 2, 3]
'Une autre chaine de caractères'
a.index('yo')
1
a.remove('yo')
a
[1, [1, 2, 3], 4, 23.9]
# Une syntaxe permet également de créer une liste non-vide :
my_list = [1, 2, 5, 8, 12, 17]
for item in my_list:
print(item)
1 2 5 8 12 17
a = "Ceci est une chaine de caractères"
print(type(a))
<class 'str'>
Les objets de ce type disposent de nombreuses méthodes :
a.lower()
a.upper()
a.isdigit()
a.isprintable()
'ceci est une chaine de caractères'
'CECI EST UNE CHAINE DE CARACTÈRES'
False
True
Comme avec les listes, on peut accéder à une position particulière ou obtenir un slice de l'objet.
a[2] # La troisième lettre
a[:12] # Jusqu'à la 12ème lettre
a[2:5] # ...
'c'
'Ceci est une'
'ci '
# À vrai dire, c'est un `iterable` comme les listes :
for letter in "abcde":
print(letter)
a b c d e
Il s'agit d'un containeur immutable (contrairement à une liste on peut pas ajouter / supprimer / modifier ses éléments) qui peut contenir des objets hétérogènes.
Comme pour les listes, on peut utiliser les crochets pour appeler ses éléments.
# On peut l'utiliser pour stocker des informations structurées
# (où le N-ième élément a toujours la même signification)
pt1 = (12.1, 34.9) # (x, y)
pt2 = (34.4, 21.1) # (x, y)
info_consumers = [
('marie', 38, 21900.12), # (name, age, salary)
('bob', 22, 13900.12),
('alice', 48, 20900.12),
]
age_mean = 0
for consumer in info_consumers:
age_mean += consumer[1] / len(info_consumers)
age_mean
36.0
Il s'agit d'une HashMap (principe clé -> valeur) relativement performante, pouvant contenir des éléments hétérogènes.
d1 = {}
d1['john'] = "1293038"
d1['eva'] = "1204004"
d1['rick'] = "1398091"
d1
{'john': '1293038', 'eva': '1204004', 'rick': '1398091'}
d1['john']
'1293038'
# Quelques méthodes des dictionnaires :
d1.get('rick')
'1398091'
d1.get('kdgjkdgjkd', "0") # avec valeur par défaut si absence de la clé
'0'
d1.keys() # Retourne une vue des clefs du dictionnaire
dict_keys(['john', 'eva', 'rick'])
d1.values() # Retourne une vue des valeurs du dictionnaire
dict_values(['1293038', '1204004', '1398091'])
# Fusion avec un autre dictionnaire
d1.update({'alice': '129874', 'alex': '2100012'})
print(d1)
{'john': '1293038', 'eva': '1204004', 'rick': '1398091', 'alice': '129874', 'alex': '2100012'}
# Tester la présence d'une clé :
'matt' in d1
False
d1['matt'] # <- oh no !
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-26-06a69f48afe9> in <module> ----> 1 d1['matt'] # <- oh no ! KeyError: 'matt'
try:
# Le bloc de code à 'surveiller' :
print(d1['bob'])
except KeyError as e:
# Si l'erreur rencontrée est de type `KeyError`
print('{} is missing 0_0'.format(e))
except Exception:
# Si un autre type d'erreur est survenu
print('Something else happened...')
else:
# Si aucune erreur ne s'est produite
print('doo')
finally:
# Ce bloc est exécuté dans tous les cas
print('We safely escaped from here !')
'bob' is missing 0_0 We safely escaped from here !
# Création d'un type d'erreur personnalisé
class UnrecoverableError(Exception): pass
if not 'bob' in d1:
# Déclenchement de cette erreur
# (en utilisant un message explicatif)
raise UnrecoverableError('Where is bob ?')
--------------------------------------------------------------------------- UnrecoverableError Traceback (most recent call last) <ipython-input-28-f5dcca34a3b6> in <module> 5 # Déclenchement de cette erreur 6 # (en utilisant un message explicatif) ----> 7 raise UnrecoverableError('Where is bob ?') UnrecoverableError: Where is bob ?
seen = set()
for item in [1, 2, 4, 1, 5, 2, 9, 4, 1, 9]:
seen.add(item)
print('{} éléments uniques : {}'.format(len(seen), list(seen)))
5 éléments uniques : [1, 2, 4, 5, 9]
s1 = {'rick', 'bob', 'alice', 'alex'}
s2 = {'john', 'eva', 'bob'}
# Des méthodes intéressantes
s1.intersection(s2) # -> {'bob'}
s2.issubset(s1) # -> False
s1.symmetric_difference(s2) # -> {'alex', 'alice', 'eva', 'john', 'rick'}
{'bob'}
False
{'alex', 'alice', 'eva', 'john', 'rick'}
Une dizaine d'autres types natifs existent. Ils sont parfois manipulés de manière moins explicite (ou moins souvent!)
fset = frozenset(seen) # <- Un `set` auquel on ne pourra plus ajouter d'éléments
print(type(fset))
1 in fset # Utile pour vérifier l'absence ou la présence d'un élément par exemple
12 in fset # ... et rapide
<class 'frozenset'>
True
False
Rappel : tout est objet en Python
isinstance(33, int)
isinstance(int, type)
isinstance(int, object)
isinstance(type, object)
issubclass(int, object)
True
True
True
True
True
isinstance(33, int) # -> True
len([1, 2, 3]) # -> 3
type(33) # -> int
dir()
pour connaitre l'ensemble des attributs d'un objets directement dans l'interpréteurenumerate()
, filter()
, map()
, max()
, min()
, range()
, reversed()
, round()
, etc.# Imprimer l'ensemble des attributs d'un objet dans l'interpréteur
li = [1, 2, 3]
print(dir(li))
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
# Still looking for Bob !
my_list = list(d1.keys())
print(my_list)
for name in my_list:
name_lower = name.lower()
if name_lower == 'bob':
print('Finally you\'re here..!')
elif name_lower == 'eva':
print('Oh hi Eva!')
else:
print('...')
['john', 'eva', 'rick', 'alice', 'alex'] ... Oh hi Eva! ... ... ...
def create_empty_consumer_info(names):
result = []
for name in names:
result.append({
"name": name, "age": None, "salary": 0
})
return result
def set_age(info_consumers, name, age):
for info in info_consumers:
if info['name'] == name:
info['age'] = age
infos = create_empty_consumer_info(my_list)
set_age(infos, 'alex', 33)
infos
[{'name': 'john', 'age': None, 'salary': 0}, {'name': 'eva', 'age': None, 'salary': 0}, {'name': 'rick', 'age': None, 'salary': 0}, {'name': 'alice', 'age': None, 'salary': 0}, {'name': 'alex', 'age': 33, 'salary': 0}]
# Avec une approche plus 'fonctionnelle' ?
infos = list(map(lambda x: {"name": x, "age": None, "salary": 0}, my_list))
# Utilisation de la fonction précédement définie
set_age(infos, 'alex', 22)
infos
[{'name': 'john', 'age': None, 'salary': 0}, {'name': 'eva', 'age': None, 'salary': 0}, {'name': 'rick', 'age': None, 'salary': 0}, {'name': 'alice', 'age': None, 'salary': 0}, {'name': 'alex', 'age': 22, 'salary': 0}]
# Une approche plus fonctionnelle et plus pythonique ?
infos = [{"name": x, "age": None, "salary": 0} for x in my_list]
# En utilisant le même type d'approche pour modifier un élément spécifique
[i for i in infos if i['name'] == 'alex'][0]['age'] = 107
infos
[{'name': 'john', 'age': None, 'salary': 0}, {'name': 'eva', 'age': None, 'salary': 0}, {'name': 'rick', 'age': None, 'salary': 0}, {'name': 'alice', 'age': None, 'salary': 0}, {'name': 'alex', 'age': 107, 'salary': 0}]
# Un rapide aperçu de l'approche orientée objet ?
class Consumer:
def __init__(self, name, age=None, salary='0'):
self.name = name
self.age = age
self.salary = salary
def __repr__(self):
return 'Consumer {}. age : {}. salary : {}'.format(self.name, self.age, self.salary)
class ConsumerInfos:
def __init__(self, consumers):
self.consumers = {c.name: c for c in consumers}
def get_by_name(self, name):
return self.consumers[name]
def __repr__(self):
return ''.join(['[','\n'.join(str(c) for c in self.consumers.values()),']'])
infos = ConsumerInfos(Consumer(name) for name in my_list)
infos.get_by_name('alex').age = 43
infos
[Consumer john. age : None. salary : 0 Consumer eva. age : None. salary : 0 Consumer rick. age : None. salary : 0 Consumer alice. age : None. salary : 0 Consumer alex. age : 43. salary : 0]
li = [1, 2, 3]
for item in li:
if item == 38:
print('38 !!!!')
else:
print('Not 38 ..')
File "<ipython-input-39-7d74bf765d5d>", line 6 print('Not 38 ..') ^ IndentationError: expected an indented block
Respecter les règles d'identations est nécessaire (comprendre obligatoire) en Python.
Ce n'est pas une contrainte lors d'une session de travail car les IDE guident la position du curseur.
Cette indentation a un rôle direct sur le contrôle du flux d'éxecution.
Elle permet d'éviter l'utilisation d'accolades (curly brackets) pour délimiter les blocs et de point-virgules pour délimiter les instructions.
# Ce code est volontairement incorrect /!\
result = []
li1 = [1, 2, 3, 4, 5, 6]
li2 = [4, 20, 31, 87, 123, 621]
# Ajoutons 1 à chaque élément
for item1, item2 in zip(li1, li2):
new_item = item1 + item2
result.append(new_item)
# Cette instruction est éxécutée une seule fois
# après que l'ensemble des itérations de la boucle ai été effectué
print(result)
[627]
result = []
li1 = [1, 2, 3, 4, 5, 6]
li2 = [4, 20, 31, 87, 123, 621]
# Ajoutons 1 à chaque élément
for item1, item2 in zip(li1, li2):
new_item = item1 + item2
result.append(new_item)
# Cette instruction est éxécutée à
# chaque itération de la boucle.
print(result)
[5, 22, 34, 91, 128, 627]
La communauté Python compte de nombreux membres (c'est un des langages les plus en vogue 1, 2), dans des thématiques variées (géospatial, astronomie, bio-informatique, etc.).
En plus de sa facilité d'apprentissage, la polyvalence du langage est une des raisons de sa forte utilisation : il est facile d'utiliser le Python pour écrire des tests pour une bibliothèque d'un autre langage ou pour faire la "glue" entre plusieurs composants d'un système.
1 : https://insights.stackoverflow.com/survey/2018#technology
2 : https://stackoverflow.blog/2017/09/06/incredible-growth-python/
La gestion des packages se fait via l'utilitaire pip
.
Contrairement à R
où les bibliothèques sont généralement installées depuis l'interpréteur du langage, en Python elles sont installées depuis le terminal du système d'exploitation.
Les bibliothèques disponible via pip
sont celle du Python Package Index : PyPI : https://pypi.org/.
Contrairement au CRAN, il s'agit d'un index non-supervisé et dans une certaine mesure on en restera conscient lorsqu'on l'utilise (risque de typosquatting, etc.).
Ce risque est toutefois très fortement réduit lors de l'utilisation du package manager d'une distribution Python telle qu'Anaconda ou Canopy qui seront présentées ensuite.
Utilisation basique :
pip install numpy
Si plusieurs installations de Python sont présentes sur le système d'exploitation (généralement sur GNU/Linux), il pourra être nécessaire de préciser pour laquelle on souhaite voir l'action réalisée:
pip3 install numpy
L'utilitaire pip
peut également être utilisé pour installer du code depuis un repository git ou depuis un dossier local par exemple.
pip install git+https://github.com/user/repo.git@branch
Spécifier avec précision la version d'une bibliothèque à installer :
pip install pandas==0.23.4
Supprimer une bibliothèque installée :
pip uninstall pandas
La documentation officielle Python est très agréable, complète (documentation de l'ensemble des fonctions natives et de l'ensemble des modules de la bibliothèques standard, exemples, tutoriels, documentations pour les développeurs, etc.) et est disponible en français.
Elle est générée avec Sphinx, outil développé à l'origine pour générer cette documentation, et dont la maturité lui permet d'être utilisé pour générer la documentation de différents types de projets informatiques.