Introduction au Python.

Python est un langage de programmation très puissant mais mais aussi simple à apprendre. Venez découvrir Python avec son interpréteur et ses généralités.

Introduction

Je vais introduire la base de Python avec vous. Cependant, je suppose certains prérequis. Premièrement je considère que vous savez ce qu'est un langage de programmation et que Python est déjà installé sur votre ordinateur. Si ce n'est pas le cas il existe déjà de nombreuses explications sur internet notamment ici. Pour ma part je travaille sur Ubuntu avec Python2.7 mais vous pouvez utiliser la version 3, je tenterai d'expliquer les différences aux moments adéquats. Selon moi une personne connaissant Python2.7 saura très bien faire du Python3, l'inverse n'est pas toujours vrai et nous verrons pourquoi.

Cours du jour

C'est parti pour la leçon du jour. Au programme: les généralités de ce langage, un nouvel interpréteur et la découverte des types et des variables. Plus globalement nous répondrons à la question: qu'est-ce que Python?

Langage interprété

Il faut d'abord savoir qu'il existe deux types de langages: interprété ou compilé! Grossièrement un langage compilé doit, avant d'être exécuter, être traduit en binaire (un autre langage). Un langage interprété quant à lui va le traduire au fur et à mesure. Comme vous pouvez vous en douter avec le titre Python est interprété !

Afin de l'utiliser il faut donc un interpréteur. Ce dernier récupère les instructions que nous lui donnons et les effectue directement. Pour avoir votre premier interpréteur il vous suffit d'entrer $ python dans votre terminal. Vous êtes alors dans votre interpréteur que vous pouvez quitter avec la commande >>> quit() (ce qui est plutôt utile). Il s'agit de l'interpréteur basique, il fonctionne très bien mais j'ai mieux à vous proposer... ;)

Le problème de l'interpréteur basique est qu'il n'y a ni autocomplétion ni de coloration syntaxique, ce qui n'est pas super agréable. Je vous conseille donc d'utiliser bpython ou ipython qui sont deux excellents outils. Nous utiliserons bpython mais sachez que ipython possède énormément de fonctions très intéressantes mais j'en parlerai plus tard avec Jupyter. De plus bpython est plus simple et suffira largement pour ce que nous allons faire! Pour l'installer vous pouvez suivre les indications ici. Bien entendu vous pouvez très bien garder l'interpréteur initial, il sera juste moins agréable à utiliser...

Vous avez votre interpréteur? Que les choses sérieuses commencent!

Notions générales

Parlons peu, parlons Python! Afin de savoir utiliser un outil il faut, selon moi, le comprendre un minimum. Je ne vais pas rentrer dans des détails très pointus (que je ne maitrises pas forcément) mais je vais tenter de vous apprendre certaines choses sur ce langage. Premièrement il faut savoir qu'il existe plusieurs Python. Oui je sais c'est un peu bizarre mais l'implémentation de référence est CPython. C'est un interpréteur de bytecode écrit en C. Cependant, il en existe d'autres comme Jython pour Java, Pyfort pour Fortran ou PyPy pour Python. Oui, cette dernière est une mise en œuvre de Python... Avec elle-même. Je vous laisse faire plus de recherches si vous êtes intéressés.

La deuxième particularité est son typage. Python est un langage au typage fort et dynamique. Qu'est-ce que ça signifie? Pour ceux qui ne connaissent pas il y a les typages fort ou faible et statique ou dynamique. La plus part des langages distinguent un entier naturel (int[eger]) et les réels (float), les caractères simples et les chaines de caractères, etc. On dit qu'ils sont fortement typés (exemple: C++), à l'inverse ceux qui le sont faiblement considèrent les variables 'juste' comme des nombres ou une autre catégorie regroupant plusieurs types (exemple: JavaScript). Ensuite il peut être statique, c'est à dire qu'une fois la variable créée elle a un type fixe qui ne changera pas. A l'inverse avec un typage dynamique un objet peut très bien changer par l'appelle d'une fonction par exemple. Ceci dépend de la muabilité...

La quoi??? La muabilité! Je sais le nom est barbare mais c'est quelque chose d'assez simple. Déjà il faut savoir que Python est un langage introsectif: c'est-à-dire que tout est objet! Il s'agit un conteneur qui a différentes informations et fonctions. Nous reverrons ça dans une prochaine leçon... Revenons pour le moment aux termes 'muable' et 'immuable'. Immuable signifie juste que la variable ne change pas en appelant une fonction dessus, la valeur reste donc la même tandis qu'un objet muable va changer de valeur 'in place'. Il est important d'avoir cette précision lors de l'utilisation d'un type afin d'éviter les mauvaises surprises. Mais comment on sait si un type est muable ou pas? Et bien il existe des fonctions 'spéciales' qui s'écrivent comme ceci: __nomfunction__. Il s'agit de fonctions "cachées" que nous n'appelons (sauf cas spéciaux) jamais directement mais par d'autres moyens. Par exemple le + appelle en réalité __add__. Et bien il faut savoir que les types immuables ont la fonction __hash__ ce qui n'est pas le cas pour la plupart des muables.

Ok, c'est très bien tout ça mais comment je fais comment pour voir les fonctions d'une classe? Et bien je vous présente deux amies: les fonctions dir() et help()! Commençons par le plus évident: help() permet d'obtenir la documentation liée à un objet, classe ou fonction. dir() quant à lui permet de voir toutes les méthodes normales et spéciales. Voici un petit exemple:

>>> dir("mot")
['__add__', '__class__', ..., ''__hash__', '__init__', ..., 'upper', 'zfill']

>>> help("mot".upper)
S.upper() -> string Return a copy of the string S converted to uppercase.

Bon parler c'est bien joli mais si on codait?

Premières instructions

Chaines de caractères

Maintenant nous allons être un peu plus actif, lancer $ bpython dans votre terminal et on va travailler un peu! Le but est de découvrir les types principaux, voir les premières normes syntaxiques et singularités. Aller, on commence avec quelque chose de super simple: les chaines de caractères! En anglais on le traduit part string ce qui est raccourci en str.

>>> my_string = "My name is FtZzy !"

>>> dir(my_string)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

Alors c'est un nouveau type donc premier réflexe: muable ou non? On retrouve le fameux __hash__ donc on dirait que non. Nous nous intéressons par exemple à la fonction lower().

>>> help(my_string.lower)
S.lower() -> string
Return a copy of the string S converted to lowercase.

>>> my_string.lower()
'my name is ftzzy !'

>>> my_string
"My name is FtZzy !"

On voit donc qu'appliquer la fonction sur la chaine ne la change pas, les strings sont donc bel et bien immuables. C'est une routine intéressante et presque indispensable à faire à chaque fois. Ça vous évitera d'aller sur internet un bon nombre de fois. Je ne m'attarde pas plus sur les chaines de caractères car nous aurons l'occasion de les revoir plus tard. Passons plutôt à un autre type souvent utilisé: les listes.

Listes

Parlons donc un peu des listes, si souvent utilisé dans tous les langages! Nous commencerons par voir comment créer une liste et récupérer ses valeurs.

>>> # Ceci est un commentaire
>>> # Création des listes

>>> my_list = [] # liste vide

>>> my_list = [4] # liste avec la valeur 4

>>> my_list = ['toto', 4, []] # liste avec plusieurs valeurs de plusieurs types

>>> my_list = list(('toto', 4, [])) # équivalent

>>> my_list = range(5) # [0, 1, 2, 3, 4]

>>> my_list = range(1, 5) # [1, 2, 3, 4]

>>> my_list = range(1, 14, 2) # [1, 3, 5, 7, 9, 11, 13]

>>> # Parcours d'une liste

>>> len(my_list) # Longueur de la liste
7

>>> my_list[0] # Récupère la première valeur
1

>>> my_list[2] # Récupère la troisième valeur
5

>>> my_list[-1] # Récupère la dernière valeur
13

>>> my_list[-7] # Récupère la première valeur
1

>>> my_list[2:6] # Sous-liste
[5, 7, 9, 11]

>>> my_list[3::3] # Autre sous-liste
[7, 13]

>>> "c" in my_list # Check si la valeur est dans la liste
False

>>> 9 in my_list
True

Maintenant que vous connaissez la base de la base on va voir un autre petit truc sur les listes...

>>> my_list = []

>>> dir(my_list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

>>> help(my_list.append)
L.append(object) -- append object to end

>>> my_list.append(1)

>>> my_list
[1]

>>> # my_list a changé de valeur: les listes sont donc muables !

>>> second_list = my_list

>>> my_list.insert(0, "0 indique la 1e case")

>>> my_list
['0 indique la 1e case', 1]

>>> second_list
['0 indique la 1e case', 1]

>>> second_list.pop()
1

>>> my_list
['0 indique la 1e case']

>>> second_list
['0 indique la 1e case']

Oulala, que s'est-il passé? Je n'ai modifié que my_list mais second_list l'a aussi été... Et bien c'est normal! Lors de la déclaration d'une variable il réserve un espace dans la mémoire et on peut récupérer cette valeur via la fonction id(), dans mon cas id(my_list) vaut 139812943134088, tout comme id(second_list). C'est parce que l'opérateur = ne fait rien d'autre que créer une référence au même objet, d'où le même id: c'est une shallow copy. Afin de comparer deux objets nous avons le mot clé is qui regarde les id, contrairement à == qui compare les valeurs. On en reparlera un peu plus loin dans cette leçon. Si vous souhaitez créer un objet totalement indépendant vous pouvez utiliser le constructeur third_list = list(my_list). Les identifiants sont maintenant différents. Poussons le problème encore plus loin: et si une liste contient d'autres listes? Et bien on va tester!

>>> first_big_list = [[0, 1], ['a', 'b']]

>>> second_big_list = list(first_big_list)

>>> second_big_list is first_big_list # 2 objets différents
False

>>> first_big_list[0] = "Hey"

>>> first_big_list
['Hey', ['a', 'b']]

>>> second_big_list
[[0, 1], ['a', 'b']]

>>> # Normal jusqu'à maintenant...

>>> first_big_list[1][0] = "ici"

>>> first_big_list
['Hey', ['ici', 'b']]

>>> second_big_list
[[0, 1], ['ici', 'b']]

Et bien le constructeur de liste effectue une copie de la liste de et ses valeurs. Cependant ces valeurs sont elles-mêmes des listes. Globalement list() donne un id différent aux 'big_lists', or elles se réfèrent toutes les deux à d'autres listes qui ont le même id. C'est pourquoi modifier une des sous-listes dans l'un la modifie aussi dans l'autre! Afin de faire la copie espérée récursivement on utilise une deep copy, que je vous propose de le revoir lors d'un prochain cours sur les collections et les import. En attendant tout est bien expliqué sur stackoverflow.

Booléens

Pour finir avec les types d'aujourd'hui on va parler des booléens. Les booléens sont des variables qui ne peuvent prendre seulement que deux valeurs: True (vrai) ou False (faux). Il s'agit d'une particularité de Python. Effectivement dans ce lanagage tout est VRAI sauf 0, False, None (objet nul) et les conteneur vide (exemples: [], "", {}, ...) grâce à la fonction __nonzero__. Nous pouvons donc écrire les choses suivantes, que nous aurons la chance de revoir.

>>> if []:
. . . . . . print("Jamais affiché")
. . . elif "a":
. . . . . . print("Yeah !")
Yeah !

Norme de syntaxe

Je finirai ce petit cours (déjà bien rempli) avec les normes de langage. Ce que je n'ai pas dit c'est que Python est un langage communautaire et afin que tout le monde puisse facilement s'approprier le code des autres ils ont défini des normes d'écriture: PEP8. Bien entendu si vous ne les suivez pas votre programme fonctionnera mais c'est une bonne pratique de s'y habituer dès le début. Vous pouvez ajouter une vérification sur votre éditeur de code facilement, ou les apprendre par coeur ici ;). Après il existe également la commande $ autopep8 qui permet de transformer un fichier afin de le rendre PEP8. Je ne ferai pas la liste des bonnes manières mais je vous laisse y jeter un œil.

Résumé

Aller on fait une petite liste des choses abordées et si ça ne vous dit rien alors revenez dessus! Python est donc un langage interprété qui nous avons utilisé avec bpython. Il bénéficie d'un typage fort et dynamique. Dans ce langage tout est objet, certains sont muables et d'autres non. Nous avons vu les fonctions dir() et help() qui nous ont aidés à découvrir les strings et les listes. On a vu avec cette dernières les différences de copies. Enfin on a fini avec les booléens, un outil dont vous ne soupçonnés pas encore le pouvoir, et PEP8.

Ça vous a plu? Regarder la suite.

Cours suivant