Agrega nuevas declaraciones a Python sin personalizar el comstackdor

Me gustaría agregar una nueva palabra clave a Python y la maravillosa respuesta de @ EliBendersky explica cómo hacerlo cambiando el código y redistribuyendo el comstackdor de Python.

¿Es posible introducir una nueva palabra clave sin cambiar el código del comstackdor? ¿Tal vez introducirlo a través de una biblioteca?

Editar:

Por ejemplo, me gustaría agregar una taquigrafía para la coincidencia de expresiones regulares agregando una palabra clave como matches que se pueden usar como:

 "You can't take the sky from me" matches '.+sky.+' 

Puedo agregar un comportamiento nuevo y personalizado utilizando transformaciones AST, pero el caso anterior fallará en un error de syntax.

No se puede introducir una nueva palabra clave sin cambiar el idioma

El analizador es la herramienta / progtwig que lee el código y decide qué tiene sentido y qué no. Aunque es una definición más bien aproximada, la consecuencia es que el lenguaje está definido por su analizador.

El analizador se basa en la gramática del lenguaje (formal), especificada en la documentación del módulo ast .

Mientras que la definición de una mera función solo introduce una nueva función sin modificar el idioma, agregar una palabra clave equivale a introducir una nueva syntax, que a su vez cambia la gramática del idioma.

Por lo tanto, agregar una nueva palabra clave, en el sentido de agregar una nueva syntax a un idioma, no se puede hacer sin cambiar el idioma de la gramática, lo que requiere editar la cadena de comstackción y ejecución.

Sin embargo…

Puede haber algunas formas inteligentes de introducir una nueva función, que se parece a una nueva syntax pero de hecho solo usa la syntax existente. Por ejemplo, el módulo goto se basa en una propiedad del lenguaje no tan conocida, que los espacios alrededor de un punto en un identificador calificado se ignoran.

Puedes probar esto por ti mismo:

 >>> l = [1, 2, 3] >>> l .append(4) >>> l [1, 2, 3, 4] >>> l. append(5) >>> l [1, 2, 3, 4, 5] 

Esto permite usar lo siguiente, que parece una nueva syntax, pero en realidad no lo es:

 label .myLabel goto .myLabel 

Ahora, el módulo goto utiliza la forma en que el intérprete trabaja internamente para realizar una interrupción de un goto a una label dada … Pero ese es otro problema.


Me gustaría añadir que Python es un lenguaje bastante abierto. Proporciona una buena cantidad de operadores poco utilizados, por ejemplo, @ . Este operador, introducido desde Python 3.5, estaba destinado principalmente para la multiplicación de matrices y __matmul__ a una llamada a __matmul__ . Tengo que decir que nunca lo he visto en código. Entonces, ¿por qué no usarlo para su propósito?

Vamos a hacerlo paso a paso. Propongo definir una clase r , que se comportará como una expresión regular.

 import re class r: def __init__(self, pattern): self.regex = re.compile(pattern) 

Ahora, quiero poder usar el operador @ con esta clase, junto con una cadena, con la semántica de una match entre la cadena y el patrón. __matmul__ método __matmul__ , de la siguiente manera:

 class r: def __matmul__(self, string): return bool(self.regex.match(string)) 

Ahora, puedo hacer lo siguiente:

 >>> r("hello") @ "hello" True >>> r("hello"] @ "world" False 

Bastante bien, pero no eso todavía. __rmatmul__ método __rmatmul__ también, por lo que simplemente __matmul__ a una llamada a __matmul__ . Al final, la clase r ve así:

 class r: def __init__(self, pattern): self.regex = re.compile(pattern) def __matmul__(self, string): return bool(self.regex.match(string)) def __rmatmul__(self, string): return self @ string 

Ahora, la operación inversa también funciona:

 >>> "hello" @ r("hello") True >>> "123456" @ r("\d+") True >>> "abc def" @ r("\S+$") False 

Esto está muy cerca de lo que intentabas, excepto que no tuve que introducir una nueva palabra clave. Por supuesto, ahora el identificador r debe estar protegido, al igual que str o list

Para su “problema” particular (acortar la manera de hacer coincidir una expresión regular), una solución sería crear una subclase de str y usar un operador binario no utilizado (por ejemplo, tal vez se podría hacer una mejor elección, desafortunadamente no podemos usar ~ como es unario)

ejemplo:

 import re class MyStr(str): def __sub__(self,other): return re.match(other,self) a = MyStr("You can't take the sky from me") print(a - '.+sky.+') print(a - '.+xxx.+') 

resultado:

 <_sre.SRE_Match object; span=(0, 30), match="You can't take the sky from me"> None 

Por lo tanto, “subvertir” la expresión regular de su objeto de cadena devuelve el objeto de coincidencia.

La desventaja es que ahora tienes que escribir literales de cadena envueltos en el nuevo objeto (no es posible definir este nuevo operador en el propio str )