Une méthode à calculer une seule fois (@lazy function ??)

Le
Laurent Claessens
Bonjour tout le monde


J'ai une classe qui a une méthode qui demande un calcul assez lourd.
Pour une instance donnée, je suis certain que la résultat ne va jamais
changer.
Seulement, pour certaines instances je n'ai pas besoin d'utiliser
cette méthode, et pour d'autres, j'aurai besoin de l'utiliser plusieurs
fois.
Donc je veux une méthode qui n'est, par défaut pas calculée, (donc
pas à calculer dans __init__). Mais je veux que si je l'appelle deux
fois, la seconde fois se contente de retourner le même résultat.

D'habitude, je fais comme ceci :

--code-

class MyClass(object):
def __init__(self,a):
self.a=a
def hard_computation(self):
return self.a+1


class MyOptimizedClass(object):
def __init__(self,a):
self.a=a
self._hard_computation=None
def hard_computation(self):
if self._hard_computation is None :
self._hard_computation=self.a+1
return self._hard_computation

x=MyClass(2)
print x.hard_computation()
print x.hard_computation() # 2+1 is computed twice !

y=MyClass(2)
print y.hard_computation()
print y.hard_computation() # 2+1 is computed only once !



Pour la classe MyClass, le calcul sera effectué à chaque appel de
hard_computation(). Pour la classe MyOptimizedClass, le calcul sera
uniquement effectué la première fois.

Question : est-ce que procéder comme cela est conseillé ?
Il me semble me souvenir de quelque chose comme @lazy_function à mettre
devant def hard_computation(self), mais je n'ai pas retrouvé. Est-ce que
quelqu'un sait ?


Bon WE
Laurent
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Laurent Claessens
Le #23095081
Il me semble me souvenir de quelque chose comme @lazy_function à mettre
devant def hard_computation(self), mais je n'ai pas retrouvé. Est-ce que
quelqu'un sait ?



Je me réponds (partiellement) à moi-même. Ce dont je me souvenais était
@lazy_attribute
dans Sage :
http://www.sagemath.org/doc/reference/sage/misc/lazy_attribute.html

Est-ce que cela existe aussi en python "pur" ?


Bon WE
Laurent
Philippe Bouige
Le #23100221
Le 05-02-2011, Laurent Claessens
Bonjour tout le monde


J'ai une classe qui a une méthode qui demande un calcul assez lourd.
Pour une instance donnée, je suis certain que la résultat ne va jamais
changer.



Est-ce que la solution ne serait pas ici ?

http://en.wikipedia.org/wiki/Memoization
http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/

memoize(function):
cache = {}
def decorated_function(*args):
if args in cache:
return cache[args]
else:
val = function(*args)
cache[args] = val
return val
return decorated_function

OU :
---+

class Memoize:
def __init__(self, fn):
self.cache = {}
self.fn = fn

def __call__(self, *args):
if self.cache.has_key(args):
return self.cache[args]
else:
object = self.cache[args] = self.fn(*args)
return object


Cordialement Philippe Bouige



cette méthode, et pour d'autres, j'aurai besoin de l'utiliser plusieurs
fois.
Donc je veux une méthode qui n'est, par défaut pas calculée, (donc
pas à calculer dans __init__). Mais je veux que si je l'appelle deux
fois, la seconde fois se contente de retourner le même résultat.

D'habitude, je fais comme ceci :

--------------------code-------------------------------------

class MyClass(object):
def __init__(self,a):
self.a=a
def hard_computation(self):
return self.a+1


class MyOptimizedClass(object):
def __init__(self,a):
self.a=a
self._hard_computation=None
def hard_computation(self):
if self._hard_computation is None :
self._hard_computation=self.a+1
return self._hard_computation

x=MyClass(2)
print x.hard_computation()
print x.hard_computation() # 2+1 is computed twice !

y=MyClass(2)
print y.hard_computation()
print y.hard_computation() # 2+1 is computed only once !


---------------------------------------------------------
Pour la classe MyClass, le calcul sera effectué à chaque appel de
hard_computation(). Pour la classe MyOptimizedClass, le calcul sera
uniquement effectué la première fois.

Question : est-ce que procéder comme cela est conseillé ?
Il me semble me souvenir de quelque chose comme @lazy_function à mettre
devant def hard_computation(self), mais je n'ai pas retrouvé. Est-ce que
quelqu'un sait ?


Bon WE
Laurent
Laurent Claessens
Le #23102691
Est-ce que la solution ne serait pas ici ?

http://en.wikipedia.org/wiki/Memoization
http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/



Oui, c'est exactement ce genre de choses que je cherchais.
Maintenant je sais surtout que je dois chercher à comprendre ce que sont
les "décorateurs" de fonctions.
C'est au programme de la prochaine fois que j'aurai du temps à y
consacrer ;)
En attendant je vais utiliser plus ou moins tel quel sans chercher à
comprendre.

merci
bonne soirée
Laurent
Alain Ketterlin
Le #23102761
Laurent Claessens
http://en.wikipedia.org/wiki/Memoization
http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/



Oui, c'est exactement ce genre de choses que je cherchais.



Cela fait beaucoup plus que ce que tu demandais (cela conserve tous les
résultats d'une fonction). Dans ton cas, si mes souvenirs sont bons, ta
fonction n'avait aucun paramètre, donc il n'y aura jamais qu'un seul
résultat à conserver. Donc on se ramène à ta solution, qui avant
l'avantage d'être simple.

Maintenant je sais surtout que je dois chercher à comprendre ce que
sont les "décorateurs" de fonctions.
C'est au programme de la prochaine fois que j'aurai du temps à y
consacrer ;)
En attendant je vais utiliser plus ou moins tel quel sans chercher à
comprendre.



Voir ci-dessus. Dans la pratique, ce n'est pas utilisable, sauf cas trà ¨s
particulier (j'imagine, je n'en ai jamais rencontré). Il faudra
vraisemblablement ajouter un test pour savoir si le résultat calculà ©
doit être conservé.

-- Alain.
Michel Claveau - MVP
Le #23103531
Bonsoir !

Un truc dans ce genre :




class cl(object):



def __init__(self):

self.resultat=None

def _resultat_(self, *bidon, **kbidon):
return self.resultat

def calcul(self, *par):
a=par[0]
b=a+par[0]
c=a+b
#...suite du calcul
self.resultat=c
self.calcul=self._resultat_
return c


a=cl()
print a.calcul(1,2,3)
print a.calcul(11,22)


?
--
Michel Claveau
Publicité
Poster une réponse
Anonyme