• Aucun résultat trouvé

Documentation strings (docstrings)

Dans le document Python Python (Page 142-149)

Les objets docstrings sont des chaînes de caractères placées au début du corps des fonctions. Ils sont automatiquement associés à la variable __doc__ de l’objet fonction par l’interpréteur.

Une fonction dotée d’un docstring

>>> # fonction explicite ...

>>> elements = [1, 2, 3]

>>> def add_one(e):

... return e + 1 ...

>>> map(add_one, elements) [2, 3, 4]

>>> # équivalent avec lambda ...

>>> map(lambda e: e + 1, elements) [2, 3, 4]

>>> def pi():

... """Renvoie une approximation du nombre Pi."""

... return 3.14 ...

>>> print(pi.__doc__)

Renvoie une approximation du nombre Pi.

ou bien :

>>> help(pi)

Help on function pi in module __main__:

pi()

Renvoie une approximation du nombre Pi.

(END)

Toutes les fonctions fournies dans Python sont dotées d’un docstring, ce qui est pra-tique pour une documentation en ligne directe. On y renseigne sur l’objectif de la fonction et sur le détail de ses paramètres.

Détails sur divmod par son docstring

Decorators

Les decorators sont issus d’un besoin de généralisation des mécanismes introduits par les fonctions classmethod() et staticmethod() apparus à la version 2.2 de Python.

En l’occurrence, pour spécifier qu’une fonction est une méthode statique ou une méthode de classe (voir les decorators pour les classes à la prochaine section), il est nécessaire de procéder à un appel à l’une des primitives en passant en paramètre la fonction.

D’un point de vue plus général aux fonctions, le principe, calqué sur le modèle exis-tant en Java (annotations), est d’effectuer un prétraitement au moment de l’appel d’une fonction.

Définition d’un prétraitement

La fonction decorate décore la fonction a_function de détails supplémentaires et la liaison se fait par function=decorate(function).

>>> print(divmod.__doc__) divmod(x, y) -> (div, mod)

Return the tuple ((x-x%y)/y, x%y). Invariant: div*y + mod == x.

À RETENIR Importance des docstrings

Les docstrings jouent un rôle relativement important en Python. Le chapitre 7 décrit précisément les con-ventions de nommage des docstrings et le chapitre 12 leur utilisation dans le cadre des tests unitaires.

>>> def decorate(function):

... function.__doc__ = 'Fonction décorée %s' % function.__doc__

... return fonction ...

>>> def a_function():

... """Ma fonction."""

... print('traitement') ...

>>> a_function = decorate(a_function)

>>> print(a_function.__doc__) Fonction décorée Ma fonction.

Pour simplifier l’écriture, les decorators introduisent un nouveau mécanisme qui permet de spécifier qu’une fonction est encapsulée dans une deuxième fonction.

Il suffit de préfixer la définition de la fonction à encapsuler par le nom de la deuxième fonction préfixé d’une arobase (@).

Définition d’un decorator

Plusieurs decorators peuvent êtres utilisés sur la même fonction : ils sont imbriqués dans l’ordre de déclaration.

Enchaînement de decorators

Cette notation étant équivalente à l’écriture ci-dessous : Équivalent explicite

Les decorators servent également à la mise en place de code patterns récurrents, comme le contrôle de types de paramètres entrants, d’enrichissement du contexte d’exécution ou de tout mécanisme pré ou post-exécution. La fonction décoratrice est déclarée une bonne fois pour toute et réutilisée en decorator.

Contrôle d’argument

>>> def decorate(function):

... function.__doc__ = 'Fonction décorée %s' % function.__doc__

... return function ...

>>> @decorate

... def a_function():

... """Ma fonction."""

... print('traitement') ...

>>> print a_function.__doc__

Fonction décorée ma fonction

@f1 @f2 @f3 def a_function():

pass

function = f1(f2(f3(function)))

>>> def only_ints(func):

... def _only_ints(arg):

... ifnot isinstance(arg, int):

... raise TypeError("'%s' doit être un entier" % str(arg))

Une fonction de décoration ne doit pas à proprement parler exécuter de code au moment de son appel, car cet appel est provoqué par l’interpréteur lorsqu’il lit la défi-nition de la fonction décorée. Il demande alors à la fonction de décoration de lui ren-voyer une fonction qui sera appelée à chaque exécution de la fonction décorée.

Quelques print permettent de mieux comprendre cette mécanique : La mécanique des decorators

File "<stdin>", line 1, in ?

File "<stdin>", line 4, in only_ints TypeError: 't' doit être un entier

... print('only_ints renvoi la capsule') ... return _only_ints

La sous-fonction _only_ints() permet donc de retourner le code à exécuter lorsque la fonction sera réellement appelée. only_ints() ici prend en paramètre la fonction à décorer et retourne la fonction à appeler.

Il est possible de passer des arguments aux decorators : l’appel devient de la forme

@fonction(parametres). Dans ce cas, la fonction utilisée doit renvoyer une fonction au format decorator classique, afin de permettre à l’interpréteur d’effectuer un appel à

decorateur(fonction).

L’enchaînement est le suivant : l’interpréteur appelle dans un premier temps la fonc-tion de décorafonc-tion, d’une manière tout à fait classique (resultat =

decorator(parametres)), puis utilise son résultat pour un appel à la fonction décorée, soit resultat(fonction).

File "<stdin>", line 1, in ?

File "<stdin>", line 4, in only_long TypeError: '45' doit être un long

>>> function(459876455L) 459876456L

Si on ajoute des print pour mettre en valeur l’enchaînement :

AVENIR Émergence des decorators

Les patterns d’utilisation des decorators émergent actuellement des travaux des développeurs de la com-munauté. Il est possible qu’à terme Python propose une liste étendue de decorators.

Classes

Sans être familier avec la programmation orientée objet (POO), on peut considérer que les classes sont similaires à des modules : des regroupements logiques de fonc-tions et de variables pour définir un comportement et un état du programme. Cette logique se retrouve dans les éléments manipulés en Python, puisque tout est objet.

Ainsi, un objet de type string regroupe des fonctions de manipulation sur la chaîne comme replace() et des variables comme __doc__.

La différence fondamentale entre un module et une classe se situe dans l’utilisation de cette dernière : elle définit un modèle d’objet que l’on peut ensuite instancier autant de fois que nécessaire. Une instance devient un objet indépendant qui con-tient les fonctions et les variables définies dans le modèle.

Définition

Le mot réservé class sert à définir un modèle en associant un certain nombre de variables et de fonctions à un nom.

La classe Voiture

Toutes les variables et les fonctions placées dans le niveau d’indentation de la classe en deviennent des membres. Ces éléments sont nommés attributs et on parle plus précisé-ment de méthodes pour les fonctions et d’attributs de données pour les variables.

La classe Car définie dans l’exemple peut ensuite être utilisée pour instancier des objets en l’appelant comme une fonction.

Instanciation

Ces deux objets de type Car sont des instances distinctes.

ALLERPLUSLOIN La programmation orientée objet

Si vous n’êtes pas familier avec les concepts de la POO, le chapitre 14 est une bonne introduction à son utilisation en Python.

>>> class Car:

... color = 'Rouge' ...

>>> car_1 = Car()

>>> car_2 = Car()

Dans le document Python Python (Page 142-149)