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):
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.
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.
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.
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.
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
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.
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.
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:
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.
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 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
Le slicing permet de sélectionner un sous ensemble dans une séquence (liste, tuple, string, etc) en spécifiant:
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.
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.
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:
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 >>>
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
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.
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.
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']
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
Python fournit un le module pdb.
import pdb
si vous utilisez l’interpréteur ipython, ipdp
pip install ipdb
Pour les tests le mot clé assert permet de lever une exception AssertionError lorsque l'expression évaluée n'est pas vraie.