C'est quoi f = 1..__truediv__
?
f
est une méthode spéciale liée sur un flottant avec une valeur de un. Plus précisément,
1.0 / x
en Python 3, invoque:
(1.0).__truediv__(x)
Preuve:
class Float(float):
def __truediv__(self, other):
print('__truediv__ called')
return super(Float, self).__truediv__(other)
et:
>>> one = Float(1)
>>> one/2
__truediv__ called
0.5
Si nous faisons:
f = one.__truediv__
Nous conservons un nom lié à cette méthode liée
>>> f(2)
__truediv__ called
0.5
>>> f(3)
__truediv__ called
0.3333333333333333
Si nous faisions cette recherche en pointillé dans une boucle serrée, cela pourrait gagner un peu de temps.
Analyse de l'arbre de syntaxe abstraite (AST)
On peut voir que l' analyse de l'AST pour l'expression nous dit que nous obtenons l' __truediv__
attribut sur le nombre à virgule flottante, 1.0
:
>>> import ast
>>> ast.dump(ast.parse('1..__truediv__').body[0])
"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"
Vous pouvez obtenir la même fonction résultante à partir de:
f = float(1).__truediv__
Ou
f = (1.0).__truediv__
Déduction
On peut aussi y arriver par déduction.
Construisons-le.
1 en soi est un int
:
>>> 1
1
>>> type(1)
<type 'int'>
1 avec un point après qu'il soit un flotteur:
>>> 1.
1.0
>>> type(1.)
<type 'float'>
Le point suivant en lui-même serait une SyntaxError, mais il commence une recherche pointée sur l'instance du flottant:
>>> 1..__truediv__
<method-wrapper '__truediv__' of float object at 0x0D1C7BF0>
Personne n'a mentionné ailleurs ce - Ceci est maintenant une « méthode liée » sur le flotteur, 1.0
:
>>> f = 1..__truediv__
>>> f
<method-wrapper '__truediv__' of float object at 0x127F3CD8>
>>> f(2)
0.5
>>> f(3)
0.33333333333333331
Nous pourrions accomplir la même fonction de manière beaucoup plus lisible:
>>> def divide_one_by(x):
... return 1.0/x
...
>>> divide_one_by(2)
0.5
>>> divide_one_by(3)
0.33333333333333331
Performance
L'inconvénient de la divide_one_by
fonction est qu'elle nécessite un autre cadre de pile Python, ce qui la rend un peu plus lente que la méthode liée:
>>> 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]
Bien sûr, si vous pouvez simplement utiliser des littéraux simples, c'est encore plus rapide:
>>> def f_3():
... for x in range(1, 11):
... 1.0/x
...
>>> timeit.repeat(f_3)
[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]
(1).__truediv__
n'est pas vraiment le même que1..__truediv__
, comme le premier appelleint.__truediv__
tandis que le second le faitfloat.__truediv__
. Alternativement, vous pouvez également utiliser1 .__truediv__
(avec un espace) `