Je suis extrêmement novice en python et je viens de rencontrer des décorateurs. Je suis encore un peu confus par eux mais j'apprends
J'essayais de faire un décorateur qui me dit combien de temps ma fonction a pris pour se terminer, mais apparemment quand j'essaye de l'utiliser sur une fonction qui devrait renvoyer quelque chose, il renvoie simplement "Aucun"
Je n'ai vu que quelques questions traitant de ce problème, mais aucune n'a vraiment aidé
Voici mon code
import time def time_it(func): # Here i make a simple decorator function that should time my decorated function def wrapper(*args, **kwargs): t1 = time.time() func(*args) t2 = time.time() total = t2 - t1 print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete") return wrapper @time_it def square(nums): # I make a function that squares every number in a list new_list = [] for n in nums: new_list.append(n ** 2) return new_list lis = [f for f in range(200000)] # i make a list with a range of 200000 print(square(lis))
désolé pour les erreurs grammaticales, je ne suis pas anglophone
3 Réponses :
Votre fonction décorée ne renvoie rien de manière explicite - donc, par défaut, elle renvoie Aucun
.
Vous pouvez capturer la sortie avant d'imprimer l'heure, et la renvoyer à la fin: p>
def time_it(func): # Here i make a simple decorator function that should time my decorated function def wrapper(*args, **kwargs): t1 = time.time() out = func(*args) t2 = time.time() total = t2 - t1 print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete") return out return wrapper
Le décorateur remplace square
par wrapper
et wrapper
ne renvoie rien. Il doit renvoyer la valeur renvoyée par la fonction encapsulée.
Voici la bonne façon de procéder:
def time_it(func): def wrapper(*args, **kwargs): t1 = time.time() try: return func(*args, **kwargs) finally: t2 = time.time() total = t2 - t1 print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete") return wrapper
J'ai changé 3 choses:
return
, afin que la valeur soit renvoyée par la fonction décorée ** kwargs
aux appels func
, car il peut être nécessaire s'il est utilisé différemment try
/ finally
, de sorte que l'impression se produise même en cas d'exception, plus cela facilite le renvoi de la valeur. Le problème est que la valeur de retour de votre fonction interne n'est pas renvoyée. Le changement est noté ci-dessous:
from functools import wraps def time_it(func): # Here i make a simple decorator function that should time my decorated function @wraps(func) def wrapper(*args, **kwargs): t1 = time.time() ## Note the change on this line -- I now store the return result from the called function result = func(*args, **kwargs) t2 = time.time() total = t2 - t1 print("The function '" + func.__name__ + "' took", str(total)[0:5], "seconds to complete") ## And then explicitly return the result return result return wrapper
Pour le décorateur, vous devez vous rappeler qu'il ne s'agit que d'une fermeture, avec une syntaxe sophistiquée. Vous devez toujours gérer vous-même les paramètres de retour de la fonction.
Quelques ajouts:
à partir des wraps d'importation de functools
et @wraps (func)
Il est probablement également préférable que l'OP utilise tous les arguments, par exemple: result = func (* args, ** kwargs)
juste au cas où ... Cela ne ferait pas non plus de mal d'utiliser functools.wraps code> ici aussi ...
Oui vous avez raison. J'ai mis à jour l'exemple pour refléter cela. Merci!
Oui, car
wrapper
renvoie toujoursNone
.