Recientemente me encontré con una sintaxis que nunca antes había visto cuando aprendí Python ni en la mayoría de los tutoriales, la ..
notación, se parece a esto:
f = 1..__truediv__ # or 1..__div__ for python 2
print(f(8)) # prints 0.125
Pensé que era exactamente lo mismo que (excepto que es más largo, por supuesto):
f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8
Pero mis preguntas son:
- ¿Cómo puede hacer eso?
- ¿Qué significa realmente con los dos puntos?
- ¿Cómo puede usarlo en una declaración más compleja (si es posible)?
Esto probablemente me ahorrará muchas líneas de código en el futuro ... :)
(1).__truediv__
realidad no es lo mismo1..__truediv__
que el primero llamaint.__truediv__
mientras que el segundo sífloat.__truediv__
. Alternativamente, también puede usar1 .__truediv__
(con un espacio) `1//8
es0
, no0.125
, en cualquier versión de Python.if (x <- 3) {...}
Respuestas:
Lo que tiene es un
float
literal sin el cero final, al que luego accede al__truediv__
método. No es un operador en sí mismo; el primer punto es parte del valor flotante y el segundo es el operador de punto para acceder a las propiedades y métodos de los objetos.Puede llegar al mismo punto haciendo lo siguiente.
Otro ejemplo
Aquí agregamos 1.0 a 2.0, que obviamente rinde 3.0.
fuente
1..toString()
La pregunta ya está suficientemente respondida (es decir, @Paul Rooney la respuesta de ) pero también es posible verificar la exactitud de estas respuestas.
Permítanme recapitular las respuestas existentes: ¡El
..
no es un solo elemento de sintaxis!Puede verificar cómo se "tokeniza" el código fuente . Estos tokens representan cómo se interpreta el código:
Entonces, la cadena
1.
se interpreta como un número, el segundo.
es un OP (un operador, en este caso el operador "obtener atributo") y__truediv__
es el nombre del método. Entonces esto es solo acceder al__truediv__
método de flotación1.0
.Otra forma de ver el bytecode generado es ensamblarlo . En realidad, esto muestra las instrucciones que se realizan cuando se ejecuta algún código:
dis
Lo que básicamente dice lo mismo. Carga el atributo
__truediv__
de la constante1.0
.Con respecto a su pregunta
Aunque es posible, nunca debe escribir código como ese, simplemente porque no está claro qué está haciendo el código. Por lo tanto, no lo use en declaraciones más complejas. Incluso iría tan lejos que no deberías usarlo en declaraciones tan "simples", al menos deberías usar paréntesis para separar las instrucciones:
esto sería definitivamente más legible, pero algo similar a:
sería aún mejor!
El enfoque que usa
partial
también conserva el modelo de datos de Python (¡el1..__truediv__
enfoque no lo hace!), Que puede demostrarse con este pequeño fragmento:Esto se debe a
1. / (1+2j)
que no se evalúa porfloat.__truediv__
pero concomplex.__rtruediv__
:operator.truediv
se asegura de que se llame a la operación inversa cuando vuelve la operación normal,NotImplemented
pero no tiene estos retrocesos cuando opera__truediv__
directamente. Esta pérdida de "comportamiento esperado" es la razón principal por la cual (normalmente) no debería usar métodos mágicos directamente.fuente
Dos puntos juntos pueden ser un poco incómodos al principio:
Pero es lo mismo que escribir:
Porque los
float
literales se pueden escribir en tres formas:fuente
1.__truediv__
no lo son?.
parece ser analizado como parte de la serie, y luego el.
de descriptor de acceso método no se encuentra.f
es un método especial vinculado en un flotante con un valor de uno. Específicamente,en Python 3, invoca:
Evidencia:
y:
Si lo hacemos:
Retenemos un nombre vinculado a ese método vinculado
Si estuviéramos haciendo esa búsqueda punteada en un circuito cerrado, esto podría ahorrarnos un poco de tiempo.
Análisis del árbol de sintaxis abstracta (AST)
Podemos ver que analizar el AST para la expresión nos dice que estamos obteniendo el
__truediv__
atributo en el número de coma flotante1.0
:Puede obtener la misma función resultante de:
O
Deducción
También podemos llegar por deducción.
Vamos a construirlo.
1 por sí mismo es un
int
:1 con un período después de que es un flotador:
El siguiente punto en sí mismo sería un SyntaxError, pero comienza una búsqueda punteada en la instancia del flotador:
Nadie más ha mencionado esto : ahora es un "método vinculado" en el flotador
1.0
:Podríamos cumplir la misma función de manera mucho más legible:
Actuación
La desventaja de la
divide_one_by
función es que requiere otro marco de pila de Python, lo que lo hace algo más lento que el método enlazado:Por supuesto, si solo puede usar literales simples, eso es aún más rápido:
fuente