Al mirar los decoradores de Python, alguien hizo la declaración de que son tan poderosos como las macros de Lisp (particularmente Clojure).
Al observar los ejemplos dados en PEP 318, me parece que son solo una forma elegante de usar funciones simples de orden superior en 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):
...
No he visto ningún código que se transforme en ninguno de los ejemplos, como se describe en Anatomy of a Clojure Macro . Además, la falta de homoiconicidad de Python podría hacer que las transformaciones de código sean imposibles.
Entonces, ¿cómo se comparan estos dos y puede decir que son casi iguales en lo que puede hacer? La evidencia parece apuntar en su contra.
Editar: Basado en un comentario, estoy buscando dos cosas: comparación de "tan poderoso como" y "tan fácil de hacer cosas increíbles con".
Respuestas:
Un decorador es básicamente solo una función .
Ejemplo en Common Lisp:
En la parte superior, la función es un símbolo (que sería devuelto por
DEFUN
) y colocamos los atributos en la lista de propiedades del símbolo .Ahora podemos escribirlo alrededor de una definición de función:
Si queremos agregar una sintaxis elegante como en Python, escribimos una macro de lector . Una macro lectora nos permite programar en el nivel de sintaxis de s-expresión:
Entonces podemos escribir:
El lector Lisp lee arriba para:
Ahora tenemos una forma de decoradores en Common Lisp.
Combinando macros y macros de lector.
En realidad, haría la traducción anterior en código real usando una macro, no una función.
El uso es como el anterior con la misma macro de lector. La ventaja es que el compilador de Lisp todavía lo ve como un llamado formulario de nivel superior : el compilador de archivos * trata especialmente los formularios de nivel superior, por ejemplo, agrega información sobre ellos en el entorno de tiempo de compilación . En el ejemplo anterior, podemos ver que la macro busca en el código fuente y extrae el nombre.
El lector Lisp lee el ejemplo anterior en:
Que luego se amplía macro en:
Las macros son muy diferentes de las macros de lector .
Las macros obtienen el código fuente, pueden hacer lo que quieran y luego devolver el código fuente. La fuente de entrada no necesita ser un código Lisp válido. Puede ser cualquier cosa y podría escribirse totalmente diferente. El resultado tiene que ser un código Lisp válido entonces. Pero si el código generado también usa una macro, entonces la sintaxis del código incrustado en la llamada a la macro podría ser nuevamente una sintaxis diferente. Un ejemplo simple: se podría escribir una macro matemática que aceptaría algún tipo de sintaxis matemática:
La expresión
y = 3 x ^ 2 - 4 x + 3
no es un código Lisp válido, pero la macro podría, por ejemplo, analizarlo y devolver un código Lisp válido como este:Hay muchos otros casos de uso de macros en Lisp.
fuente
En Python (el lenguaje) los decoradores no pueden modificar la función, solo envolverla, por lo que definitivamente son mucho menos potentes que las macros lisp.
En CPython (el intérprete), los decoradores pueden modificar la función porque tienen acceso al código de bytes, pero la función se compila primero y el decorador puede manipularla, por lo que no es posible alterar la sintaxis, cosa lisp-macro -equivalente tendría que hacer.
Tenga en cuenta que los lisps modernos no usan expresiones S como bytecode, por lo que las macros que trabajan en listas de expresiones S definitivamente funcionan antes de la compilación de bytecode como se señaló anteriormente, en python el decorador se ejecuta después.
fuente
Es bastante difícil usar decoradores Python para introducir nuevos mecanismos de flujo de control.
Es casi trivial usar macros Common Lisp para introducir nuevos mecanismos de control de flujo.
De esto, probablemente se deduce que no son igualmente expresivos (elijo interpretar "poderoso" como "expresivo", ya que creo que lo que realmente quieren decir).
fuente
s/quite hard/impossible/
Sin duda, está relacionada con la funcionalidad, pero desde un decorador de Python no es trivial modificar el método que se está llamando (ese sería el
f
parámetro en su ejemplo). Para modificarlo, podría volverse loco con el módulo ast ), pero estaría en una programación bastante complicada.Sin embargo, se han hecho cosas a lo largo de esta línea: consulte el paquete macropy para ver algunos ejemplos realmente alucinantes.
fuente
ast
cosas de transformación en python no son iguales a las macros de Lisp. Con Python, el lenguaje fuente debe ser Python, con las macros Lisp el lenguaje fuente transformado por una macro puede ser, literalmente, cualquier cosa. Por lo tanto, la metaprogramación de Python solo es adecuada para cosas simples (como AoP), mientras que la metaprogramación Lisp es útil para implementar potentes compiladores eDSL.