Tout Python

Apprendre Python en dix minutes (ou à peine plus)
19 Janvier 2015

Cet article est un brouillon.

This article is a draft.

Cet article présente la totalité de la syntaxe de Python, et quelques éléments de la librarie standard. Il devrait être un support d’apprentissage suffisant pour une personne expérimentée en programmation, mais n’est pas destiné aux débutantEs. {: .lead}

  • {:toc}

(On peut ne pas lire cette introduction)

Python est un langage interprété, à typage fort implicite, qui permet d’intervenir en profondeur sur l’environnement d’exécution.

Il y a deux versions majeures actuellement supportées : Python 2.x (actuellement 2.7) et 3.x (actuellement 3.3). Ce document ne traite que de la 3.x, qui est partiellement incompatible avec la syntaxe et la librairie standard des branches 2.x.1

J’ai divisé ce document en “cercles”. Les cercles vont des fonctionnalités de base généralistes aux subtilités plus profondes du langage.

Premier cercle : les fondamentaux

Hello, world!

print ("Hello, world !")

Typage

Le typage est fort, sans conversion implicite:

a = 14 # a est un entier
b = " canards-lapins"
print(a + b) # Erreur ! int + str n'est pas défini.
print(str(a) + b) # "14 canards-lapins"
a = "quatorze" # a est désormais une chaîne
print(a + b) # "quatorze canards-lapins"

La ligne 3 ici produit l’erreur suivante:

Traceback (most recent call last):
    File "<pyshell#2>", line 1, in <module>
    print(a + b) # Erreur ! int + str n'est pas défini.
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Le langage ne sait pas “additionner” un entier et une chaîne. L’opérateur + est défini pour opérer soit sur deux chaînes (dans ce cas là, il concatène) soit sur deux valeurs numériques (et dans ce cas il additionne).

Types élémentaires

i = 14              # Entier
f = 14.23           # Flottant
c = 3.2j            # Complexe
s1 = "canard-lapin" # Chaîne
s2 = 'canard-lapin' # Chaîne (identique à la précédente)
s3 = """s3 est:
Une longue chaîne.
rien de plus."""    # 's3 est:\nUne longue chaîne.\nrien de plus.'

Les entiers sont automatiquement en précision arbitraire (ie, pas de débordement, mais une conversion automatique en long, long long, etc.). Pas de limite haute, à part la mémoire de la machine:

def fact(n):
    if not n: return 0;
    ret = 1
    while n > 1:
        ret *= n
        n -= 1
    return ret

print(fact(4000))
    # 18288019515140650133147431755739190442173777107304392197064526954208959797973177
    # 36485037028687048410733644304156928557175467246186154355733394261561795699671674
    # 52848315973174988187609374828049804195765129487206105589281297880978006205934295
    # 377053267406244538842850917439517567461444473... etc. (12674 chiffres)

Opérateurs

Opérateurs numériques

Les opérateurs numériques sont standards à quelques détails près:

  • / est l’opérateur de division décimale : 3/2==1.5

  • // est l’opérateur de division décimale : 3//2==1

  • ** est l’opérateur de puissance : 3**2==9

  • Les opérateurs ont une variante couplée avec l’affectation, +=, -=, *=, etc. a += b équivaut à a = a + b.

Opérateurs logiques

Les opérateurs logiques se notent en toutes lettres:

a = 3

v1 = not a == 3
v2 = a==2 or a==3
v3 = a%2 and a<12

Opérateurs de chaîne

Conteneurs de données

Il y en a quatre : la liste, le dictionnaire, l’ensemble et le tuple. Python étant un langage objet, les classes sont traitées juste après. Les conteneurs ne sont pas typés, et peuvent contenir n’importe quoi.

  • Une liste (list) est un tableau classique. Elle contient des objets ordonnés référencés par un index.
  • Un dictionnaire (dict) est un tableau associatif ordinaire. Il contient des objets référencés par un index arbitraire (certains types ne sont néanmoins pas utilisables comme index). Un tableau n’est pas ordonné.
  • Un ensemble (set) est aussi un objet très classique. C’est une liste non ordonnée.
  • Un tuple (n-uplet) (tuple) est une liste immutable.

Listes

Ce que le reste du monde appelle un tableau:

a = [1,2,3]  # a == [1, 2, 3]
a.append(4)  # a == [1, 2, 3, 4]
a[2]=100     # a == [1, 2, 100, 4]

Dictionnaires

Tableau associatif (hashmap):

a = { "un": 1, "deux": 2, "trois":3 }
print(a["un"]) # 1
a["quatre"] = 4
print(a) # {'deux': 2, 'quatre': 4, 'un': 1, 'trois': 3}
         #              ^ un dict n'est pas ordonné.

Ensembles

Un ensemble est une liste non ordonnée. Il n’autorise pas de doublons.

a = {1, 2, 3} # {1, 2, 3}
a.add(4)      # {1, 2, 3, 4}
a.add(4)      # {1, 2, 3, 4} : pas de doublons.
a.add(5)      # {1, 2, 5, 4, 3}
         #             ^ un set n'est pas ordonné.

N-uplets (tuples)

Un tuple est un ensemble immutable ordonné de n éléments.

a = (1, 2, 3, "canards", "lapins")
print ( a[2] )  # 3
a[3] = "chiens" # Erreur: impossible d'affecter une valeur.
Note

À cause de l’usage des parenthèses, construire un tuple à un seul élément ne consiste pas à écrire (a), car (a) == a. Si a n’est pas itérable, tuple(a) fonctionne, mais s’il l’est, le tuple sera créé avec le contenu de a. La bonne syntaxe est (a,), avec une virgule après l’élément:

a = "abc" # Les chaînes sont des itérables
tuple(a) # == ('a', 'b', 'c')
(a,) # == (a)

Initialisation et conversion entre conteneurs

On peut initialiser un conteneur avec la syntaxe simplifiée présentée plus haut, ou plus explicitement, en invoquant son constructeur:

l = list()    # Une liste vide
d = dict()    # Un dictionnaire vide
s = set()     # Un ensemble vide
t = tuple()   # Un tuple vide - généralement inutile, puisqu'on ne peut pas l'étendre.

Chaque constructeur a pour paramètre optionnel un objet itérable. Ainsi, on peut convertir aisément les list, set et tuple entre eux:

l = [1, 2, 3] # [1, 2, 3]
t = tuple(l2) # (1, 2, 3)

Les données sont passées par valeur:

l = [1, 2, 3] # [1, 2, 3]
t = tuple(l2) # (1, 2, 3)
l[2] = 12

Résumé

Type
list
dict
set
tuple

Ce sont les conteneurs natifs, il en existe d’autres dans le paquet collections.

Les structures logiques

Les blocs

Contrairement au reste du monde, Python ne délimite pas ses blocs par des paires d’accolades ou begin … end. Un bloc commence par le caractère : et se poursuit par du code indenté par rapport à la déclaration. Le bloc se termine quand l’indentation revient au niveau précédent. Par exemple, un simple if:

a = 3
b = 3

if a==b:
    print("Après vérification,")
    print("a et b ont la même valeur.")
else:
    print("a et b sont différents.")

print("Fin du programme")

Autrement dit, l’indentation a une valeur sémantique. Le niveau d’indentation n’a pas d’importance, le code ci-dessous est parfaitement valide, bien que pas idéal niveau lisibilité.

if a==b:
                                            print ("Identiques.")
else:
 print ("Différents")

De la même façon, si l’usage d’espaces est conseillé, on peut indenter avec des tabulations. La seule exigence étant de ne jamais mélanger les deux méthodes (espaces/tabs). De plus, l’identation doit par contre être constante: en fermant un bloc, on doit revenir au niveau précédent. Ce code est juste, car le else a exactement le même niveau d’indentation que le if qu’il suit.

if a==b:
    if a>=0:
        print ("Identiques et positifs ou nuls.")
    else:
        print ("Identiques et négatifs.")

Quelle est la “bonne” indentation fait partie des grands trolls pythonesques. La meilleure solution est de se donner une valeur et de s’y tenir. 4 ou 8 espaces ou (xor !) une tabulation est un bon point de départ. Par contre, mélanger les espaces et les tabulations (\t) est une erreur de syntaxe.

L’instruction pass

Le problème évident des blocs indentés est qu’il est impossible de commenter tout le contenu sans supprimer le bloc lui-même. Dans l’exemple ci-dessus, le code devient invalide si un seul if est commenté. Python prévoit une opération qui ne fait rien (comme NOP/NOOP dans la plupart des assembleurs): pass

if a==b:
    if a>=0:
        # print ("Identiques et positifs ou nuls.")
        pass
    else:
        print ("Identiques et négatifs.")

Sans le pass, cet exemple est invalide.

Tests et structures conditionnelles

Tests if

Le if est redoutablement simple, et fonctionne comme partout ailleurs, à ceci près que la condition ne se met pas nécessairement entre parenthèses:

if a==2:
    print("a vaut deux")
elif a==4:
    print("a vaut quatre")
elif a%2:
    print("a est un impair")
else:
    print("a est pair mais ne vaut ni deux ni quatre")

Rien de bien remarquable, à part que “sinon si” se note elif.

l’«opérateur ternaire»

Il existe, mais est beaucoup plus verbeux que dans d’autres langages:

print ( "a est impair" if a%2 else "a est pair" )

Il est construit pour être prochain de l’anglais : ce qui se note couramment a ? b : c s’écrit donc en Python b if a else c.

Boucles et structures itératives

Fonctions et paramètres

Une fonction se définit très banalement par le mot clé def, son nom la liste de ses paramètres entre parenthèses suivi de :.

Second cercle : classes, objets, modules

Objets et classes

Généralités

Python gère la programmation orientée objet:

class MyClass (object):

    def show(self):
        print(self.a)

    def __init__(self, a):
        self.a = a

a = MyClass(12)
a.show()      # Affiche "12"

Toute méthode d’une classe reçoit implicitement l’objet d’où elle est appelée comme premier paramètre. Il est de convention de nommer ce premier paramètre self dans la définition de la méthode. Ici, show() est défini comme show(self), mais appelé comme show(). Lorsque la méthode est appelée sur un objet, l’interpréteur passe implicitement le premier paramètre, qui est ici a. L’appel a.show() ci dessus est en fait l’exact équivalent de:

a = MyClass(12)
MyClass.show(a)

Implémentation

Il est important de noter qu’en Python, à peu près toute la logique objet est une sorte de “sucre syntaxique” collé sur un langage procédural. Ce n’est pas un défaut du langage mais plutôt une des propriétés qui le rend profondément bidouillable.

Un objet est fondamentalement un dictionnaire de ses membres. Le dictionnaire est d’ailleurs accessible, c’est un pseudo-membre nommé __dict__:

# Avec MyClass défini comme dans l'exemple précédent
a = MyClass(12)
print(a.__dict__)  # {'a': 12}

Et une classe ? C’est exactement la même chose:

print(MyClass.__dict__)
# {
    # '__dict__': <attribute '__dict__' of 'MyClass' objects>,
    # '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
    # '__doc__': None,
    # '__init__': <function MyClass.__init__ at 0x1006bf290>,
    # '__module__': '__main__',
    # 'show': <function MyClass.show at 0x1006a2290>
#}

Méthodes statiques

Autrement dit, il n’y a pas de méthodes statiques, mais toute méthode peut être invoquée comme méthode statique, en l’appelant depuis la classe et non depuis un objet. Une méthode qui ne prend aucun paramètre ne peut être appelée que de manière statique. Appelée depuis un objet, l’interpréteur essaierait de lui passer l’objet en premier paramètre, et produirait donc une erreur. Dit autrement, pour tout objet o d’une classe C ayant une méthode m(self), C.m(o) est strictement la même chose que o.m(). m(self) recevra dans les deux cas l’unique paramètre self= o. Si la méthode prend d’autres paramètres, ils sont passés à la suite.

Par contre, les attributs initialisés au niveau de la classe (et pas du constructeur, sans référence à self donc) sont statiques.

class Counter(object):
    c = 0
    d = 0

    def print(self):
        print("Cet objet: "+str(self.c))
        print("La classe: "+str(Counter.d))

    def increment(self, x):
        self.c += x

    # Le constructeur __init__(self) n'est pas nécessaire ici.

a = Counter()
b = Counter()

a.print()
b.print()

a.increment(12)

a.print()
b.print()

Modules

Troisième cercle : agir sur l’environnement d’exécution


  1. Python 3 fournit un outil, 2to3, qui transforme du code Python 2.x en 3.x. L’inverse n’est pas possible.