Eu tenho um decorador como abaixo.
def myDecorator(test_func):
return callSomeWrapper(test_func)
def callSomeWrapper(test_func):
return test_func
@myDecorator
def someFunc():
print 'hello'
Eu quero melhorar este decorador para aceitar outro argumento como abaixo
def myDecorator(test_func,logIt):
if logIt:
print "Calling Function: " + test_func.__name__
return callSomeWrapper(test_func)
@myDecorator(False)
def someFunc():
print 'Hello'
Mas este código dá o erro,
TypeError: myDecorator () recebe exatamente 2 argumentos (1 fornecido)
Por que a função não é passada automaticamente? Como faço para passar explicitamente a função para a função de decorador?
Respostas:
Como você está chamando o decorador como uma função, ele precisa retornar outra função que é o decorador real:
A função externa receberá quaisquer argumentos que você passar explicitamente e deverá retornar a função interna. A função interna receberá a função a ser decorada e retornará a função modificada.
Normalmente, você deseja que o decorador altere o comportamento da função envolvendo-a em uma função de wrapper. Aqui está um exemplo que opcionalmente adiciona registro quando a função é chamada:
A
functools.wraps
chamada copia coisas como o nome e docstring para a função de wrapper, para torná-la mais semelhante à função original.Exemplo de uso:
fonte
functools.wraps
é aconselhável - ele retém o nome original, docstring, etc. da função agrupada.myDecorator
aqui) de decorador. Isso é conveniente para um usuário do decorador, mas pode ser confuso quando você está tentando escrever um.log_decorator
pega um argumento padrão, você não pode usar@log_decorator
, deve ser@log_decorator()
Apenas para fornecer um ponto de vista diferente: a sintaxe
é equivalente a
Em particular,
expr
pode ser o que você quiser, contanto que seja avaliado como um chamável. Em particular ,expr
pode ser uma fábrica de decoradores: você fornece alguns parâmetros e ela fornece um decorador. Então, talvez a melhor maneira de entender sua situação seja comoque pode então ser encurtado para
Claro, uma vez que parece como
decorator_factory
um decorador, as pessoas tendem a nomeá-lo para refletir isso. O que pode ser confuso quando você tenta seguir os níveis de indireção.fonte
Só quero adicionar alguns truques úteis que permitirão tornar opcionais os argumentos do decorador. Também permitirá reutilizar o decorador e diminuir o aninhamento
fonte
Apenas outra maneira de fazer decoradores. Acho que essa maneira é a mais fácil de envolver minha cabeça.
fonte
Agora, se você quiser chamar uma função
function1
com um decoradordecorator_with_arg
e, neste caso, a função e o decorador usam argumentos,fonte