P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ I DON'T SUFFER FROM INSANITY, I ENJOY EVERY MINUTE OF IT Articles | Connexion
 
~Fonctions anonymes

Précédent  
  Python  
  Suivant
 Présentation

Certaines notations introduites par le langage de Guido Van Rossum donnent accès à des expressions extrêmement concises. Nous allons aborder à présent l'utilisation des fonctions anonymes dont le but se veut de rendre plus concis encore votre code.
 Sommaire


 Lambda, quidam ?

Les fonctions anonymes, ou fonctions lambda, se définissent comme des fonctions ne possédant pas de nom. Cette caractéristique semble de prime abord interdire leur usage. Comment pourrions-nous en effet appeler une fonction ne possédant pas de nom ? Lors de notre introduction aux fonctions Python, nous avons découvert la possibilité d'assigner une fonction à une "variable". Ceci nous permettra de faire appel aux fonctions anonymes. Auparavant, nous allons découvrir comment émuler l'opérateur ternaire de condition présent dans les langages C, C++ ou encore Java.


 A trois c'est mieux

Les trois langages précédemment cités offrent l'opportunité de rédiger une condition de type if/else en une seule ligne grâce à un opérateur ternaire. Voyons un exemple simple en Java:

if (condition)
  System.out.println("Vrai");
else
  System.out.println("Faux");
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Nous pouvons condenser ces quatres lignes en une seule :

System.out.println((condition ? "Vrai" : "Faux"));
       
      
JextCopier dans Jext
Voici la forme exacte de cet opérateur : "expression de condition ? si vrai : si faux". Cet opérateur "retourne" l'évaluation de l'expression "si vrai" ou "si faux". Python ne propose aucun opérateur de ce genre. Toutefois, nous pouvons utiliser des astuces pour y parvenir. Ainsi, nous pourrions réécrire l'exemple ci-dessus en Python :

print condition and "Vrai" or "Faux"
       
      
JextCopier dans Jext
L'expression logique "condition and si vrai or si faux" conduit au même comportement que l'opérateur ternaire évoqué tantôt. Néanmoins, cette astuce masque un danger. Imaginons le code suivant :

a = ""
b = "Faux"
print 1 and a or b
       
      
JextCopier dans Jext
Ce code devrait produire l'affichage de la valeur de la variable "a". Or il n'en est rien car Python évalue la variable "a" comme une valeur fausse. En Python, les types booléens n'existent pas. Une valeur "vide" ou "nulle" correspond à la valeur logique fausse. Ainsi, notre petit exemple provoquera l'affichage de la variable "b" ! Nous pouvons y remédier aisément en faisant appel aux listes :

print (1 and [a] or [b])[0]
       
      
JextCopier dans Jext
En plaçant une valeur nulle dans une liste, nous n'obtenons pas une valeur nulle et contournons ainsi ce petit écueil avec grâce.


 Halte quidam !

La déclaration d'une fonction anonyme se réalise en Python par l'intermédiaire du mot-clé "lambda". Les fonctions anonymes différent des fonctions classiques sur deux points : les paramètres ne sont pas donnés entre parenthèses et le mot-clé return se voit exclu. La ligne de code ci-dessous démontre l'usage d'une fonction anonyme pour calculer le carré du chiffre 4 :

print (lambda x: x * x)(4)
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
La fonction anonyme ici déclarée nécessite un paramètre, x. Le résultat du calcul x * x se voit retourné sans mention du mot-clé return. L'ensemble (lambda x: x * x) se voulant une fonction, nous pouvons en rédiger immédiatement l'appel en ajoutant à sa suite le passage d'un paramètre.

Cet exemple ne reflète pas l'intérêt des fonctions anonymes. Voyons un extrait de programme pouvant calculer soit le cosinus soit le sinus d'une valeur :

calcul = methode and (lambda x: cos(x)) or (lambda x: sin(x))
       
      
JextCopier dans Jext
Dans cet exemple, si la variable methode contient la valeur logique vraie, la fonction calcul(x) calculera le cosinus se son paramètre. Dans le cas contraire, elle calculera le sinus du nombre. Nous pouvons donc appeler ensuite calcul(5). Voyons un autre exemple d'application des fonctions anonymes. Nous possédeons un programme dont le but s'avère d'éliminer les espaces superflus dans une chaîne de caractères. Notre programme offre deux méthodes de fonctionnement : l'élimination des espaces en début et fin de chaîne uniquement, ou l'élimination des espaces superflus en tout point de la chaîne.

L'objet chaîne de Python comprend trois méthodes indispensables à notre programme. L'élimination d'espaces superflus en début ou fin de chaîne se produit lors d'un appel à la méthode strip(). Python octroît la chance de pouvoir éliminer ces espaces en début ou fin uniquement. Nous faisons ici référence aux méthodes lstrip() et rstrip(). La suppression des espaces inclus au centre de la chaîne de caractères relève de l'astuce. La fonction split() découpe la chaîne en une liste de mots. Les séparateurs employés sont les espaces, les tabulations et les retours à la ligne. Utilisée conjointement avec la méthode join([]), nous pourrons éliminer efficacement les indésirables. La fonction join() prend en paramètre une liste. Une nouvelle chaîne va être créée, construite à l'aide des éléménts de la liste. Chaque élément sera séparé du suivant par la chaîne sur laquelle la fonction join() s'applique.

Le code source suivant place ainsi chaque mot de la phrase sur une ligne :

phrase = "quel boulet ce zdar"
print "\n".join(phrase.split())
       
      
JextCopier dans Jext
Nous demandons ici d'insérer le caractère de retour à la ligne entre chaque mot de la phrase. Pour mieux comprendre le fonctionnement de split(), examinons la liste formée par l'appel de phrase.split() :

['quel', 'boulet', 'ce', 'zdar']
       
      
JextCopier dans Jext
Le programme "lambda.py" présenté dans le listing numéro un requière deux paramètres donnés sur la ligne de commande. L'exécution de : lambda.py 0 " je suis ici " affichera " je suis ici". En changeant le premier paramètre de 0 à 1, nous verrions alors apparaître : " je suis ici".


 Manipuler des variables externes

Considérons une application dont le fonctionnement impose d'incrémenter des valeurs avec un pas donné. Ce pas pouvant varier au cours de l'exécution de l'application. Certes la méthode que nous allons étudier ne s'avère pas efficace mais possède le mérite de démontrer la puissance des fonctions anonymes. Le listing numéro deux propose une fonction normale retournant une fonction anonyme. La fonction anonyme créée par l'intermédiaire de notre fonction increment(pas) renverra le résultat du calcul "x + pas". Ainsi ces lignes sont valables :

f  = increment(12)
print f(30) # 42
f = increment(10)
print f(1) # 11
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Ce petit exemple a pour intérêt d'illustrer l'accès à des variables externes depuis des fonctions lambda. Si nous avions défini une fonction lambda calculant x + n, puis que n se voyait changé au cours de l'exécution, nous n'aurions pu garantir les résultats des calculs. En passant par une fonction normale, nous nous assurons que le paramètre "n" aura une valeur constante tant que la fonction ne se verra pas recréée. Pour vous en convaincre, vous pouvez exécuter les quelques lignes du listing numéro trois et considérer les sorties provoquées.


 Listings

Listing 1

from sys import argv
if len(argv) == 3:
    f = (argv[1] == 0) and (lambda s: s.strip()) or (lambda s: " ".join(s.split()))
    print f(argv[2])
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Listing 2

def increment(pas)
  return (lambda x: x + pas)
       
      
JextCopier dans Jext
Listing 3

y = 3
f = lambda x: x * y
print f(2)
y = 10
print f(2)
       
      
JextCopier dans Jext


par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006


Précédent  
  Python  
  Suivant

 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE