Ao olhar para os decoradores de Python, alguém fez a afirmação de que eles são tão poderosos quanto as macros Lisp (principalmente o Clojure).
Olhando para os exemplos dados no PEP 318 , parece-me que eles são apenas uma maneira elegante de usar funções simples de ordem superior antigas no Lisp:
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
...
Não vi nenhum código se transformar em nenhum dos exemplos, como descrito em Anatomia de uma macro Clojure . Além disso, a falta de homoiconicidade do Python poderia impossibilitar as transformações de código.
Então, como esses dois se comparam e você pode dizer que eles são iguais no que você pode fazer? As evidências parecem apontar contra.
Editar: Com base em um comentário, estou procurando duas coisas: comparação entre "tão poderoso quanto" e "tão fácil de fazer coisas incríveis".
Respostas:
Um decorador é basicamente apenas uma função .
Exemplo no Lisp comum:
Acima, a função é um símbolo (que seria retornado por
DEFUN
) e colocamos os atributos na lista de propriedades do símbolo .Agora podemos escrever em torno de uma definição de função:
Se queremos adicionar uma sintaxe sofisticada como no Python, escrevemos uma macro de leitor . Uma macro de leitor nos permite programar no nível da sintaxe da expressão s:
Podemos então escrever:
O leitor Lisp lê acima para:
Agora, temos uma forma de decoradores no Common Lisp.
Combinando macros e macros de leitor.
Na verdade, eu faria a tradução acima em código real usando uma macro, não uma função.
O uso é como acima com a mesma macro do leitor. A vantagem é que o compilador Lisp ainda o vê como um formulário de nível superior - o compilador de arquivos * trata os formulários de nível superior especialmente, por exemplo, adiciona informações sobre eles no tempo de compilação ambiente de . No exemplo acima, podemos ver que a macro analisa o código-fonte e extrai o nome.
O leitor Lisp lê o exemplo acima em:
Que então é expandida para a macro:
Macros são muito diferentes das macros do leitor .
As macros passam o código fonte, podem fazer o que quiserem e depois retornar o código fonte. A fonte de entrada não precisa ser um código Lisp válido. Pode ser qualquer coisa e pode ser escrito totalmente diferente. O resultado deve ser um código Lisp válido. Mas se o código gerado também estiver usando uma macro, a sintaxe do código incorporado na chamada de macro poderá ser novamente uma sintaxe diferente. Um exemplo simples: pode-se escrever uma macro matemática que aceite algum tipo de sintaxe matemática:
A expressão
y = 3 x ^ 2 - 4 x + 3
não é um código Lisp válido, mas a macro poderia, por exemplo, analisá-la e retornar um código Lisp válido assim:Existem muitos outros casos de uso de macros no Lisp.
fonte
No Python (a linguagem), os decoradores não podem modificar a função, apenas envolvê-la, portanto são definitivamente muito menos poderosos do que as macros lisp.
No CPython (o intérprete), os decoradores podem modificar a função porque têm acesso ao bytecode, mas a função é compilada primeiro e pode ser manipulada pelo decorador, portanto, não é possível alterar a sintaxe, uma coisa lisp-macro -equivalente precisaria fazer.
Observe que os lisps modernos não usam expressões S como bytecode, portanto, as macros que trabalham nas listas de expressões S definitivamente funcionam antes da compilação do bytecode, conforme observado acima, em python o decorador corre atrás dele.
fonte
É muito difícil usar decoradores Python para introduzir novos mecanismos de fluxo de controle.
É quase trivial usar macros Common Lisp para introduzir novos mecanismos de controle de fluxo.
A partir disso, provavelmente decorre que eles não são igualmente expressivos (eu escolho interpretar "poderoso" como "expressivo", pois acho que eles realmente significam).
fonte
s/quite hard/impossible/
É certamente uma funcionalidade relacionada, mas, para um decorador Python, não é trivial modificar o método que está sendo chamado (esse seria o
f
parâmetro no seu exemplo). Para modificá-lo, você pode enlouquecer com o módulo ast ), mas precisará de uma programação bastante complicada.No entanto , algumas coisas foram feitas: verifique o pacote de macropy para obter alguns exemplos realmente alucinantes.
fonte
ast
material de transformação em python não é igual às macros Lisp. No Python, a linguagem de origem deve ser Python; nas macros Lisp, a linguagem de origem transformada por uma macro pode ser, literalmente, qualquer coisa. Portanto, a metaprogramação do Python é adequada apenas para coisas simples (como AoP), enquanto a metaprogramação do Lisp é útil para implementar poderosos compiladores eDSL.