¿Qué es f = 1..__truediv__
?
f
es un método especial vinculado en un flotante con un valor de uno. Específicamente,
1.0 / x
en Python 3, invoca:
(1.0).__truediv__(x)
Evidencia:
class Float(float):
def __truediv__(self, other):
print('__truediv__ called')
return super(Float, self).__truediv__(other)
y:
>>> one = Float(1)
>>> one/2
__truediv__ called
0.5
Si lo hacemos:
f = one.__truediv__
Retenemos un nombre vinculado a ese método vinculado
>>> f(2)
__truediv__ called
0.5
>>> f(3)
__truediv__ called
0.3333333333333333
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 flotante 1.0
:
>>> import ast
>>> ast.dump(ast.parse('1..__truediv__').body[0])
"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"
Puede obtener la misma función resultante de:
f = float(1).__truediv__
O
f = (1.0).__truediv__
Deducción
También podemos llegar por deducción.
Vamos a construirlo.
1 por sí mismo es un int
:
>>> 1
1
>>> type(1)
<type 'int'>
1 con un período después de que es un flotador:
>>> 1.
1.0
>>> type(1.)
<type 'float'>
El siguiente punto en sí mismo sería un SyntaxError, pero comienza una búsqueda punteada en la instancia del flotador:
>>> 1..__truediv__
<method-wrapper '__truediv__' of float object at 0x0D1C7BF0>
Nadie más ha mencionado esto : ahora es un "método vinculado" en el flotador 1.0
:
>>> f = 1..__truediv__
>>> f
<method-wrapper '__truediv__' of float object at 0x127F3CD8>
>>> f(2)
0.5
>>> f(3)
0.33333333333333331
Podríamos cumplir la misma función de manera mucho más legible:
>>> def divide_one_by(x):
... return 1.0/x
...
>>> divide_one_by(2)
0.5
>>> divide_one_by(3)
0.33333333333333331
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:
>>> def f_1():
... for x in range(1, 11):
... f(x)
...
>>> def f_2():
... for x in range(1, 11):
... divide_one_by(x)
...
>>> timeit.repeat(f_1)
[2.5495760687176485, 2.5585621018805469, 2.5411816588331888]
>>> timeit.repeat(f_2)
[3.479687248616699, 3.46196088706062, 3.473726342237768]
Por supuesto, si solo puede usar literales simples, eso es aún más rápido:
>>> def f_3():
... for x in range(1, 11):
... 1.0/x
...
>>> timeit.repeat(f_3)
[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]
(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) `