Mateus Berger
Mateus Berger

Reputation: 13

Decorators having strange behavior

I am trying to learn how decorators works and how to use them, but I'm getting a strange behavior. The idea is to create a wrapper method to calculate the execution time (I know, have other ways to do this) and wrap a method called "cadastra_usuario_no_banco", this method just get a sleep and returns true.

import time
def tempo_de_execucao(funcao_original):
  def envolucro(*args, **kargs):
    tempo_inicio = time.time()
    retorno = funcao_original(*args, **kargs)
    tempo_total = time.time() - tempo_inicio
    print(" -------- envolucro --------")
    print("A função retornou", retorno)
    print(int(tempo_total), "Segundos para a execução")
  
  return envolucro

@tempo_de_execucao
def cadastra_usuario_no_banco():
  print ("iniciando cadastro de usuário")
  time.sleep(1)
  print ("Cadastro de usuário efetuado com sucesso!")
  return True

But, when I try to run using the follow instructions

a = tempo_de_execucao(cadastra_usuario_no_banco)
print(a())

I am getting two times the print and returns from the wrapper.

iniciando cadastro de usuário            # Execution of the wrapped method
Cadastro de usuário efetuado com sucesso!
 -------- envolucro --------             # The decorated execution 
A função retornou True                   # the correct return of the wrapped method
1 Segundos para a execução               # the time of the execution
A função retornou None                   # the strange behavior, that is not supposed to be here
1 Segundos para a execução               # is not supposed to be here too
None                                     # the print of the wrapper method (this is correct)

Why this is happening?

Upvotes: 1

Views: 28

Answers (1)

Gabriel A.
Gabriel A.

Reputation: 641

As stated on the comments and from the docs:

@dec2
@dec1
def func(arg1, arg2, ...):
    pass

Is equivalent to

def func(arg1, arg2, ...):
    pass
func = dec2(dec1(func))

Decorators are functions that takes another function as arguments and returns a new function.

So you are calling it twice when you put @tempo_de_execucao above cadastra_usuario_no_banco and also called tempo_de_execucao(cadastra_usuario_no_banco), which resulted in tempo_de_execucao(tempo_de_execucao(cadastra_usuario_no_banco))

Upvotes: 1

Related Questions