Table des matières

,

Python: introduction

Quelques notes à propos des spécificités du langage Python basées sur mes écueils.

Python a été conçu avec l'objectif d'être lisible, compréhensible faciitant son accès et les échanges de codes. Les choix de conceptions ont été guidés par pragmatisme et non par dogmatisme.

Langage portable avec une grosse base de code: calcul scientifique, traitement de données, web, embarqué etc.

Python permet de devélopper/ concevoir rapidement (PoC):

Droits et licences

Python appartient a la PSF (Python Software Fondation) qui est une organisation à but non lucratif. La licence est permissive et permet de l'utiliser à des fins commerciales.

Évolution du langage

Toute proposition concernant l'évolution du langage est débattue démocratiquement au travers des PEPs puis tranchée par le BDFL1) qui se traduit par Dictateur bienveillant à vie.

Bref historique

Première version python 1.0 sortie en 1994. Version 2 en 2000. Grosse rupture de compatibilité entre la version 2 et la version 3. Langage stable et maintenu.

Librairie standard: ensemble des utilitaires packagés, distribués et maintenus avec Python.

EDI et Interpréteurs

IDLE (prononcer Aïdeul) est l'EDI proposé par la librairie standard mais il existe de nombreux EDI supportant python on pourra citer: PyCharm,Syder,Emacs etc

ipython est interpréteur proposant des couleurs, de l'autocomplétion, une documentation en ligne. Il offre un mode interactif plus user friendly que l’interpréteur python original.

$ sudo apt-get install ipython
 
# ou sous les versions plus récentes de Debian/xUbuntu
$ sudo apt-get install ipython3

Pour plus de détails concernant l'installation voir le wiki installer_interpreteurs.

Jeux de caractères

Par défaut l’interpréteur python2.7 attend des scripts utilisant le jeu de caractères ASCII. Si l'on utilise un autre jeu de caractère il faut le spécifier. Pour cela insérer au plus tôt (avant que la première conversion ait lieu) dans le fichier la ligne suivante:

# coding: utf8 

L'encodage utilisé pour écrire le fichier de script est à paramétrer dans l'éditeur ou l'EDI. Il faut toujours savoir quel encodage on utilise pour écrire son code et privilégier utf-8 (mise en œuvre de l'encodage universel unicode).

Généralement pour un fichier script l’entête comprend également le chemin de l’interpréteur à appeler:

#!/usr/bin/python
# coding: utf8

Cet entête permet d'appeler le script depuis le bash (si les droits de lecture et d’exécution sont correctement positionnés) directement:

./monscript.py

Variables

Une variable référence un objet. Python gère deux espaces:

Lors d'une déclaration telle que:

>>> msg = 'Bonjour!'

3 étapes:

La valeur de toute variable est une référence à un objet. Le typage est dynamique mais le langage est fortement typé. En python le type n'est pas lié à la variable qui référence l'objet mais il est lié à l'objet. L'objet garde son type durant toute l’exécution du programme. La variable par contre peut référencer différents objets qui vont

En python les noms des variables ne peuvent pas commencer par un chiffre. Le nom se compose des caractères alphanumériques sans caractères spéciaux. Les noms sont sensibles à la casse de caractère.

Prendre l'habitude de nommer correctement ses variables avec des labels explicites. Python intègre un système de génération automatique de la documentation à partir du code.

Par convention les variables sont en minuscules. Par convention également les variables “privées” sont préfixées par le caractère tiret bas '_' (confère PEP 008 http://legacy.python.org/dev/peps/pep-0008/#descriptive-naming-styles).

Dans tous les cas il est fortement déconseillé d'utiliser le formalisme __variable__ car utilisé par le langage.

Types de base

En Python tout est objet. Le type d'une variable est déterminé dynamiquement, pas de déclaration de variable avant l'utilisation. La fonction type() renvoi le type de l'objet passé en paramètre: Le type est important puisqu'il détermine quelles méthodes peuvent être appelées, quel comportement peut avoir l'objet. Parmi les types de base (built-in types) ont distingue les types mutables et les types immuables:

Type Mutablilité
int, float immuable
complex,bool immuable
str immuable
list mutable
dict mutable
set mutable
frozenset immuable

Un objet mutable peut être modifié en place. Un objet immuable ne peut être modifié, python doit réallouer un espace mémoire différent et mettre à jour la référence.

>>> # initialisation d'une variable de type entier:
... 
>>> a = 3
>>> type (a)
<type 'int'>
>>> # une variable flottante
... 
>>> f = 2.1
>>> type (f)
<type 'float'>
>>> # une variable chaine de caractères
... 
>>> c = 'c'
>>> type(c)
<type 'str'>
>>> c = 'ma chaine'
>>> type(c)
<type 'str'>

Remarques:

  1. La fonction type() retourne le type de l'objet référencé par la variable passée en paramètre.
  2. Python ne distingue pas caractère et chaîne de caractères, le type est 'str' (string).

La fonction isinstance() est plus largement utilisée pour la mise en œuvre des mécanismes d'héritage. Elle permet de savoir si un objet est d'un type donné.

De plus comme python est un langage à typage dynamique, isinstance() permet de s'assurer qu'une variable passée à une fonction à l’exécution est du type attendu, puisque contrairement à un langage typé statiquement, aucune garantie ne peut être apportée en amont.

Depuis python 3.5 les Type hints ou annotations de types permettent d'expliciter les suppositions qui sont faites par le programmeur pour le bon fonctionnement de son code. Totalement optionnelles et meme si elles sont présentes elles ne sont pas utilisées à l'exécution par l'interpréteur. Cependant elles permettent a des outils externes comme mypy d'effectuer des contrôles poussés de correction de code.

La liste

Une liste est un ensemble ordonné d'objets pouvant être de différents types. Les éléments de l'ensemble sont accessible via leur index.

>>> ma_liste = ['toto', 2, 2.1, 'z']

Le contenu d'une liste peut être modifié, on peut ajouter/retirer des éléments à l'aide des méthodes pop() et insert(). On peut également réaffecter un élément de la liste via l'index:

>>> ma_liste[0] = 'tata'
>>> ma_liste.pop(2)
2.1
>>> ma_liste.insert(3, 2.5)
>>> print (ma_liste)
['tata', 2, 'z', 2.5]

Notes plus détaillées à propos des listes en Python.

Le tuple

Le tuple est un objet séquence très proche de la liste, sa principale différence est d'être immuable. Le tuple contient un ensemble ordonné et figé d'objets pouvant être de types différents. On ne peut pas ajouter/supprimer/modifier les éléments d'un tuple. Le principal avantage d'un tuple est le temps d’accès à l'information bien plus court que la liste.

# La syntaxe de déclaration d'un tuple utilise les parenthèse:
>>> tuple = (1, 'toto', 2.2, True);
 
# La syntaxe abrégée de déclaration d'un tuple
>>> t2 = 1, 'tata', 'tutu'
>>> print t2
(1, 'tata', 'tutu')
 
# Si le tuple a un seul élément, bien terminer la déclaration par la virgule lors de l'utilisation de la notation abrégée
>>> t3 = 'test',
>>> print t3
('test',)
 
>>> tuple[1] = 'tata' # Réaffecter un élément d'un tuple provoque une erreur.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Chaines, listes et tuples sont des séquences, c'est à dire des structures de données ordonnées dont les éléments sont indexés et accessibles via leur index.

Slicing

Le slicing permet de sélectionner un sous ensemble dans une séquence (liste, tuple, string, etc) en spécifiant:

  1. l'index du premier élément
  2. l'index du dernier élément+1
  3. le pas

Remarque 1: Si les arguments ne sont pas spécifiés, ils ont des valeurs par défaut (min, max et pas de 1).

Remarque 2: si le pas est négatif on parcourt la variable en sens inverse, pratique pour inverser une chaîne.

>>> texte="un joli texte"
>>> sous_chaine=texte[3:7]
>>> print(sous_chaine)
joli
 
>>> sous_chaine=texte[:7]
>>> print(sous_chaine)
un joli
 
>>> sous_chaine=texte[::-1]
>>> print(sous_chaine)
etxet iloj nu

Notes plus détaillées à propos des tuples.

Le dictionnaire

Un dictionnaire est un ensemble dynamique non ordonné (on parle aussi de tableau associatif). On accède aux élément via la clé.

# déclaration d'un dictionnaire
>>> d = {'prenom': 'yoann', 'nom': 'BEZILLE', 'age' : 32, 42: 'test'}

Remarque: Pour copier un dictionnaire utiliser la méthode copy()

Confère wiki dictionnaires pour plus de détails.

Définition d'un objet

class monType(object):
"""Toute classe par defaut herite du type de base object"""
    def __init__(self,...):
    """Le constructeur de la classe monType"""
 
    def methode_1(self,...):
 
    def methide_2(self,...):

Remarques:

  1. Attention le premier argument des méthodes est toujours self.
  2. Toute classe de base hérite d'object.

Instanciation d'une objet

mon_objet = maClasse(valeur1, valeur2, valeur3)

Pour instancier un objet de la classe maClasse, j'utilise ne nom de la classe et entre parenthèses je place les valeurs à transmettre au constructeur.

Exemple Se placer dans le dossier ~/dev/python contenant le fichier compte.py et lancer l’interpréteur python

>>> import compte
>>> mon_compte = compte.compte("2221");
>>> mon_compte.depot(2000000000);
>>> mon_compte.affiche()
le solde du compte '2221'est 2000000000.00
>>>

Paradigme objet

En python tout est objet, quelques méthodes d'utilité générale:

>>> # La variable c1 référence un objet str
>>> c1 = 'say'
 
>>> # création d'une variable c2 référencant le meme objet
>>> c2 = c1
 
>>> c2 is c1
True
 
>>> print(f"adresse c1: {id(c1):0x}")                                                          
adresse c1: 7fc861d4b0b0
 
>>> print(f"adresse c2: {id(c2):0x}")                                                          
adresse c2: 7fc861d4b0b0
 
>>> # Comme un objet str est immuable la concaténation 
>>> # ci-dessous produit une nouvelle référence associée a c1
c1 += ' hello'
 
>>> c2 is c1                                                                                   
False
 
>>> print(f"adresse c1: {id(c1):0x}")                                                          
adresse c1: 7fc8535cf6b0

Import et modules

Pour utiliser une fonction présente dans un fichier, utiliser la directive import avec le nom de fichier sans le suffixe .py

Remarque: dans un module, les variables globales sont accessibles. Ils est possible de modifier la valeur de la variable du module, cela peut être problématique: pour éviter cela on utilisera les objets.

Tester si le script est directement appelé

Il est possible de tester si le script est appelé directement ou via un import avec le code ci-dessous:

# Déclaration variables et directives importables
# par d'autres scripts
 
if __name__ == "__main__":
  # Le Bloc ci dessous n'est exécuté que
  # lorsque le script est appelé directement
  # mais pas lorsqu'il est importé

Ce branchement conditionnel est souvent utilisé pour des tests unitaires.

L' introspection

Les objets python savent qui ils sont, c'est l'introspection. La fonction dir() permet de lister les attributs/méthodes de tout objet.

>>> dir (ma_liste)
['__add__', '__class__', '__contains__', '__delattr__',..., 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

La documentation

Python intègre nativement la documentation au code (c'est la documentation en ligne contenue dans l'attribut doc d'une instance). Lors de la définition d'une classe ou d'une méthode, ajouter un texte entre triple guillemets sous la définition pour qu'elle soit intégrée (c'est la “doc string”)

Remarque: La position du commentaire est importante. Seuls les commentaires entre triples guillemets sous la déclaration seront exportés. Attention a bien indenter le commentaire.

Pour obtenir de l'aide, depuis l’interpréteur utiliser la commande help(), cela fonctionne meme sur les types de base:

help(str)

La commande dir() permet de lister les symboles existants au sein d'un module:

>>> import math
>>> dir(math)
'__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
>>>

La commande pydoc se charge d'extraire et de formater la doc incluse dans le code. Pour consulter la documentation d'un module nommé test.py

Remarque: Pour les scripts python3 utiliser pydoc3

$ pydoc test.py

Débogage des scripts

Python fournit un le module pdb.

import pdb

si vous utilisez l’interpréteur ipython, ipdp

pip install ipdb

Tests et tests unitaires

Pour les tests le mot clé assert permet de lever une exception AssertionError lorsque l'expression évaluée n'est pas vraie.

Références

1)
Benevolent Dictator For Life