Eu tenho algo parecido com o seguinte. Basicamente, preciso acessar a classe de um método de instância de um decorador usado no método de instância em sua definição.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
O código como está fornece:
AttributeError: o objeto 'function' não tem atributo 'im_class'
Eu encontrei perguntas / respostas semelhantes - o decorador Python faz a função esquecer que ela pertence a uma classe e Get class no decorador Python - mas elas dependem de uma solução alternativa que captura a instância em tempo de execução ao capturar o primeiro parâmetro. No meu caso, chamarei o método com base nas informações coletadas de sua classe, portanto, mal posso esperar a chegada de uma chamada.
inspect.getmro(cls)
para processar todas as classes básicas no decorador de classe para oferecer suporte à herança.inspect
o resgate stackoverflow.com/a/1911287/202168Desde o python 3.6, você pode usar
object.__set_name__
para fazer isso de uma maneira muito simples. O documento afirma que__set_name__
é "chamado no momento em que o proprietário da classe proprietária é criado". Aqui está um exemplo:Observe que ele é chamado no momento da criação da classe:
Se você quiser saber mais sobre como as classes são criadas e, em particular, exatamente quando
__set_name__
é chamado, você pode consultar a documentação em "Criação do objeto de classe" .fonte
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
embora eu use o Python 3.6+ por um longo tempo.hello
não é um método, mas sim um objeto do tipoclass_decorator
.if TYPE_CHECKING
para definirclass_decorator
como um decorador normal retornando o tipo correto.Como outros apontaram, a classe não foi criada no momento em que o decorador é chamado. No entanto , é possível anotar o objeto de função com os parâmetros do decorador e, em seguida, redecorar a função no
__new__
método da metaclasse . Você precisará acessar o__dict__
atributo da função diretamente, pois pelo menos para mim,func.foo = 1
resultou em um AttributeError.fonte
setattr
deve ser usado em vez de acessar__dict__
Como sugere Mark:
Este código mostra como isso pode funcionar usando o pós-processamento automático:
A saída produz:
Observe que neste exemplo:
Espero que isto ajude
fonte
Como as formigas indicaram, você não pode obter uma referência para a classe de dentro da classe. No entanto, se você estiver interessado em distinguir entre classes diferentes (não manipular o objeto de tipo de classe real), você pode passar uma string para cada classe. Você também pode passar quaisquer outros parâmetros que desejar para o decorador usando decoradores de estilo de classe.
Impressões:
Além disso, consulte a página de Bruce Eckel sobre decoradores.
fonte
@decorator('Bar')
em vez de@Decorator('Bar')
.O que o flask-classy faz é criar um cache temporário que ele armazena no método, então ele usa outra coisa (o fato de que o Flask registrará as classes usando um
register
método de classe) para realmente embrulhar o método.Você pode reutilizar esse padrão, desta vez usando uma metaclasse para que possa agrupar o método no momento da importação.
Na aula real (você pode fazer o mesmo usando uma metaclasse):
Fonte: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
fonte
O problema é que quando o decorador é chamado a classe ainda não existe. Experimente isto:
Este programa irá gerar:
Como você vê, terá que descobrir uma maneira diferente de fazer o que deseja.
fonte
Aqui está um exemplo simples:
O resultado é:
fonte
Essa é uma pergunta antiga, mas me deparei com venusiana. http://venusian.readthedocs.org/en/latest/
Parece ter a capacidade de decorar métodos e fornecer acesso à classe e ao método enquanto o faz. Observe que o chamado
setattr(ob, wrapped.__name__, decorated)
não é a maneira típica de usar venusiano e, de certa forma, vai contra o propósito.De qualquer forma ... o exemplo abaixo está completo e deve ser executado.
fonte
A função não sabe se é um método no ponto de definição, quando o código do decorador é executado. Somente quando é acessado por meio do identificador de classe / instância, ele pode saber sua classe / instância. Para superar essa limitação, você pode decorar por objeto descritor para atrasar o código de decoração real até o tempo de acesso / chamada:
Isso permite que você decore métodos individuais (classe estática):
Agora você pode usar o código do decorador para introspecção ...
... e para mudar o comportamento da função:
fonte
</sigh>
Como outras respostas apontaram, decorador é uma coisa funcional, você não pode acessar a classe à qual esse método pertence, pois a classe ainda não foi criada. No entanto, está totalmente ok usar um decorador para "marcar" a função e, em seguida, usar técnicas de metaclasse para lidar com o método mais tarde, porque no
__new__
estágio, a classe foi criada por sua metaclasse.Aqui está um exemplo simples:
Usamos
@field
para marcar o método como um campo especial e lidar com ele na metaclasse.fonte
if inspect.isfunction(v) and getattr(k, "is_field", False):
deveria sergetattr(v, "is_field", False)
.Você terá acesso à classe do objeto no qual o método está sendo chamado no método decorado que seu decorador deve retornar. Igual a:
Usando sua classe ModelA, aqui está o que isso faz:
fonte
Eu só quero adicionar meu exemplo, pois ele contém todas as coisas que eu poderia pensar para acessar a classe a partir do método decorado. Ele usa um descritor como sugere @tyrion. O decorador pode pegar argumentos e passá-los para o descritor. Ele pode lidar com um método em uma classe ou uma função sem uma classe.
fonte