Oct 252010
 

Vous connaissez surement cette astuce de dev qu’est le Monkey Patch (voir article wikipedia). En résumé, ça permet d’étendre ou de modifier le code sans modification du code original. Bien entendu, on ne peut monkey patcher que des langages dynamiques.

En python, pour monkey patcher une classe, par exemple, on fait :

class NewKlass :
…..
…..

from project.apps import modtest
modtest.Klass = NewKlass

Rien de bien difficile. Mais compliquons un peu les choses. Imaginons que notre classe Klass soit une classe qui nous convient en partie, mais pas complétement. Certaines fonctions nous conviennent parfaitement, mais pas d’autre. Et pour corser le tout, il faudrait qu’on rajoute des données membres à la classe. On ne peut donc pas ‘juste’ monkey patcher les fonctions qui ne nous plaisent pas…

Comment faire ?

Il faudrait pouvoir dériver de la classe qu’on veut monkey patcher, avant de la monkey patcher.. Mais ce n’est surement pas possible non ? Et ben si. Et c’est très facile.

On commence par écrire notre nouvelle classe :

from project.apps.modtest import Klass as OldKlass

class NewKlass(OldKlass) :
….
….

et ensuite on monkey patch, comme précédemment :

from project.apps import modtest
modtest.Klass = NewKlass

Une précision par contre, lorsque vous allez définir les fonctions dans NewKlass, vous alelz peut être vouloir appeler la fonction mère de la fonction que vous définissez (par exemple dans les models django, on appelle souvent le save de la fonction mère, dans le save de notre fonction)

sauf que là, il faut faire attention si vous faites :

class NewKlass(OldKlass) :
….
….

    def save(self, *args, **kwargs) :
        super( NewKlass,self).save(*args, **kwargs)

vous avez droit à une bonne récursion infinie. Parce que oui, la fonction mère de NewKlass c’est OldKlass, qui est en fait NewKlass, vu qu’on la monkey-patchée.

Il faut donc appeler utiliser la classe grand-mère de NewKlass, en faisant un

class NewKlass(OldKlass) :
….
….

    def save(self, *args, **kwargs) :
        GrandMereNewKlass.save(self,*args, **kwargs)

Petit Rajout : On me demande qui est GrandMereNewKlass. GrandMereNewKlass est en fait MereOldKlass. ou comme le propose @daks_ OldKlass.__base__ (D’ailleurs la question de ‘est ce que ça marche avec de l’héritage multiple qu’il pose dans le même tweet, reste entière 🙂 ).

Bon alors, on sait tous que le monkey Patching, c’est à utiliser avec de grande précaution. Et que bidouiller ainsi en dérivant de la classe que l’on veut monkey patchée c’est tout sauf safe. Mais bon, c’était la question du jeudi de la semaine dernière. ‘Peut-on monkey patcher une classe par une de ses classes filles ?’.

La réponses est donc oui.

Mais ce n’est pas à mettre entre toutes les mains.

Sorry, the comment form is closed at this time.