Voir la section "Justification" de PEP 424 , qui a introduit __length_hint__
et propose un éclairage sur la motivation:
Être en mesure de pré-allouer des listes, en fonction de la taille attendue, estimé par __length_hint__
, peut être une optimisation importante. Disponible a été observé pour exécuter du code plus rapide que PyPy, simplement parce que de cette optimisation être présent.
En outre, la documentation pour object.__length_hint__
vérifie le fait que c'est purement une fonction d'optimisation:
Appelés à mettre en oeuvre operator.length_hint()
. Doit retourner une durée estimée de l'objet (qui peut être supérieure ou inférieure à la longueur réelle). La longueur doit être un entier >= 0
. Cette méthode est purement une optimisation et n'est jamais requise pour l'exactitude.
Donc, __length_hint__
est ici car elle peut aboutir à quelques belles optimisations.
PyObject_LengthHint
, essaie d'abord d'obtenir une valeur de object.__len__
(si elle est définie) et puis essaye de voir si object.__length_hint__
est disponible. Si il n'y a, elle renvoie une valeur par défaut de 8
pour les listes.
listextend
, qui est appelée à partir d' list_init
que Eli a déclaré, dans sa réponse, a été modifié en fonction de ce PEPS à offrir cette optimisation pour tout ce qui définit soit une __len__
ou __length_hint__
.
list
n'est pas le seul qui bénéficie de cette situation, bien sûr, bytes
d'objets:
>>> bytes(Foo())
len
getitem 0
...
b'\x00\x01\x04\t\x10\x19'
donc, dois - bytearray
objets, mais seulement lorsque vous extend
leur:
>>> bytearray().extend(Foo())
len
getitem 0
...
et tuple
objets qui créent un intermédiaire de la séquence de remplir eux-mêmes:
>>> tuple(Foo())
len
getitem 0
...
(0, 1, 4, 9, 16, 25)
Si quelqu'un se promène exactement pourquoi 'iter'
est imprimé avant d' 'len'
dans la classe Bar
, et non après, comme il arrive avec la classe Foo
:
C'est parce que si l'objet en main définit un __iter__
Python sera la première à l'appeler pour obtenir de l'itérateur, permettant ainsi l'exécution de l' print('iter')
trop. La même chose ne se produise pas, si elle tombe en arrière à l'aide de __getitem__
.