Pergunta

Eu quero construir classes para uso como decoradores com os seguintes princípios intactos:

  1. Deve ser possível colocar vários desses decoradores de classe no topo off 1 função.
  2. O ponteiro nome da função resultante deve ser indistinguível da mesma função sem um decorador, salvar talvez só por que tipo / classe que é.
  3. pedindo o decoradores não deve ser relevante a não ser que realmente mandatado pelos decoradores. Ie. decoradores independentes poderiam ser aplicados em qualquer ordem.

Isto é para um projeto Django, e no caso específico que eu estou trabalhando agora o método precisa de 2 decoradores, e para aparecer como uma função normal do Python:

@AccessCheck
@AutoTemplate
def view(request, item_id) {}

@AutoTemplate muda a função para que em vez de retornar um HttpResponse, ele só retorna um dicionário para utilização no contexto. A RequestContext é usado, e o nome do modelo é inferida a partir do nome do método e do módulo.

@AccessCheck adiciona verificações adicionais sobre o usuário com base no item_id.

Eu estou supondo que é apenas para obter o direito construtor e copiar os atributos adequados, mas que atributos são estes?

A seguir decorador não vai funcionar como eu descrevo:

class NullDecl (object):
    def __init__ (self, func):
        self.func = func
    def __call__ (self, * args):
        return self.func (*args)

Como demonstrado pelo seguinte código:

@NullDecl
@NullDecl
def decorated():
    pass

def pure():
    pass

# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));

Além disso, tentar e adicionar no construtor NullDecl, e ele vai trabalhar para o primeiro decorador, mas não a segunda "func impressão nome .." - como o nome vai estar ausente

Refined eduffy 's resposta um pouco, e parece funcionar muito bem:

class NullDecl (object):
    def __init__ (self, func):
        self.func = func
        for n in set(dir(func)) - set(dir(self)):
            setattr(self, n, getattr(func, n))

    def __call__ (self, * args):
        return self.func (*args)
    def __repr__(self):
        return self.func
Foi útil?

Solução

A classe decorador fazer nada ficaria assim:

class NullDecl (object):
   def __init__ (self, func):
      self.func = func
      for name in set(dir(func)) - set(dir(self)):
        setattr(self, name, getattr(func, name))

   def __call__ (self, *args):
      return self.func (*args)

E então você pode aplicá-lo normalmente:

@NullDecl
def myFunc (x,y,z):
   return (x+y)/z

Outras dicas

O decorador módulo ajuda você a escrever decoradores de preservação de assinatura.

E a PythonDecoratorLibrary pode fornecer exemplos úteis para decoradores.

Para criar um decorador que envolve funções em um assunto que torná-los indistinguível da função original, o uso functools.wraps.

Exemplo:


def mydecorator(func):
    @functools.wraps(func):
    def _mydecorator(*args, **kwargs):
        do_something()
        try:
            return func(*args, **kwargs)
        finally:
            clean_up()
    return _mydecorator

# ... and with parameters
def mydecorator(param1, param2):
    def _mydecorator(func):
        @functools.wraps(func)
        def __mydecorator(*args, **kwargs):
            do_something(param1, param2)
            try:
                return func(*args, **kwargs)
            finally:
                clean_up()
        return __mydecorator
    return _mydecorator

(minha preferência pessoal é criar decoradores usando funções, não classes)

A ordenação dos decoradores é o seguinte:


@d1
@d2
def func():
    pass

# is equivalent to
def func():
    pass

func = d1(d2(func))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top