Outils personnels
Vous êtes ici : Accueil Python Quoi de neuf dans Python 2.5 PEP 309: Application partielle de fonction

PEP 309: Application partielle de fonction

Par Benjamin Poulain - Dernière modification 18/04/2008 21:03
Contributeurs : Bozo_le_clown
Python License

Python 2.5 apporte un nouveau module dédié à la programmation fonctionnelle : functools. Pour le moment ce nouveau module comporte trois fonctions : partial(), update_wrapper() et le décorateur wraps(). La fonction partial() sert à créer des applications de fonction partielle, qui ne sont rien d'autre que des appels de fonctions dont certains arguments ont déjà été remplis. La fonction update_wrapper() et le décorateur wraps() servent à copier de l'information d'un objet décoré dans son décorateur.

Le module functools sert à contenir les outils nécessaires à la programmation fonctionnelle. Si ne connaissez pas la programmation fonctionnelle, vous aurez une définition sur l'article de Wikipedia.

Un outil utile de ce module est la fonction partial(). Pour des programmes écrits dans un style fonctionnel, vous voudrez parfois construire des variantes de fonctions existantes qui ont certains paramètres déjà remplis. Considérez une fonction python f(a, b, c); Vous pourriez construire une nouvelle fonction g(b, c) qui est équivalente à f(1, b, c). Cette construction s'appelle une "application partielle de fonction".

partial prend en argument la fonction source et les arguments fixés : (fonction, arg1, arg2, ..., kwarg1=valeur1, kwarg2=valeur2). L'objet résultant est callable. Vous utilisez donc celui-ci pour invoquer fonction avec les arguments fixés.

Voici un exemple simple mais réaliste :

import functools

def log (message, sous_systeme):
"Ecrit le contenu de 'message' dans le sous-système spécifié."
print '%s: %s' % (sous_systeme, message)

serveur_log = functools.partial(log, sous_systeme='serveur')
serveur_log('Unable to open socket')

Voici un autre exemple venant d'un programme utilisant PyGTK. Ici un menu contextuel est construit dynamiquement. Le callback (fonction de rappel) fourni pour le menu est une version partielle de la méthode open_item() où le premier argument à été fourni.

...
class Application:
def open_item(self, path):
...
def init(self):
open_func = functools.partial(self.open_item, item_path)
popup_menu.append( ("Ouvrir", open_func, 1) )

Un autre fonction du nouveau module functools est la fonction update_wrapper(wrapper, wrapped) qui vous aide à écrire des décorateurs polis. La fonction update_wrapper() copie le nom, le module et l'attribut docstring dans un fonction wrapper si bien que les listing d'appels de la fonction décorée sont plus faciles à comprendre. Par exemple vous pourriez écrire:

def mon_decorateur(f):
def enveloppe(*args, **kwds):
print 'Appel de la fonction décorée'
return f(*args, **kwds)
functools.update_wrapper(enveloppe, f)
return enveloppe

Maintenant, si vous décorez une fonction à l'aide de mon_decorateur, la fonction décorateur possédera le docstring de la fonction décorée mais aussi des attributs supplémentaires donnant des informations sur la fonction décorée.

wraps() est un décorateur qui peut être utilisé à l'intérieur de vos propres décorateurs pour copier l'information de la fonction décorée. Une version alternative de l'exemple précédent utilisant wraps() serait :

def mon_decorateur(f):
@functools.wraps(f)
def enveloppe(*args, **kwds):
print 'Appel de la fonction décorée'
return f(*args, **kwds)
return enveloppe

Actions sur le document