1
votes

La fonction décorée renvoie "Aucun"

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


1 commentaires

Oui, car wrapper renvoie toujours None .


3 Réponses :


0
votes

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


0 commentaires

3
votes

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:

  • a ajouté un return , afin que la valeur soit renvoyée par la fonction décorée
  • a ajouté ** kwargs aux appels func , car il peut être nécessaire s'il est utilisé différemment
  • a ajouté le bloc try / finally , de sorte que l'impression se produise même en cas d'exception, plus cela facilite le renvoi de la valeur.


0 commentaires

3
votes

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)


2 commentaires

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 ici aussi ...


Oui vous avez raison. J'ai mis à jour l'exemple pour refléter cela. Merci!