Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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

5 réponses
Avatar
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

5 réponses

Avatar
Laurent Claessens
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
Avatar
Philippe Bouige
Le 05-02-2011, Laurent Claessens a écrit :
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
Avatar
Laurent Claessens
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
Avatar
Alain Ketterlin
Laurent Claessens writes:

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.
Avatar
Michel Claveau - MVP
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