Python 3.0 - les méthodes dict renvoient des vues - pourquoi?
-
19-08-2019 - |
Question
Méthodes dict dict.keys (), dict.items () et dict.values ??() renvoie & # 8220; views & # 8221; au lieu de listes. http://docs.python.org/dev/3.0/whatsnew//3.0 .html
Tout d’abord, en quoi une vue est-elle différente d’un itérateur? Deuxièmement, quel est l'avantage de ce changement? Est-ce juste pour des raisons de performance?
Cela ne me semble pas intuitif, c’est-à-dire que je demande une liste de choses (donnez-moi toutes vos clés) et que je reçois autre chose. Est-ce que cela va dérouter les gens?
La solution
Vous obtenez effectivement une liste. Ce n'est tout simplement pas une copie de la liste interne, mais quelque chose qui agit comme s'il s'agissait d'une liste mais ne représente que l'état interne.
C'est la même chose que dans Java (et probablement dans beaucoup d'autres langages / environnements).
La raison principale en est que, dans de nombreux cas d'utilisation, renvoyer une liste complètement isolée est inutile et inutile. Il faudrait copier tout le contenu (qui peut être peu ou pas).
Si vous souhaitez simplement parcourir les clés, il n'est pas nécessaire de créer une nouvelle liste. Et si vous en avez réellement besoin sous forme de liste séparée (en tant que copie), vous pouvez facilement créer cette liste à partir de la vue.
Autres conseils
Joachim Sauer explique très bien pourquoi une liste
n'est pas renvoyée. Mais cela pose la question de savoir pourquoi ces fonctions ne renverraient pas d’itérateurs, comme le font itéritems
etc. dans Python 2.
Un itérateur est beaucoup plus restrictif qu'un conteneur. Par exemple, un itérateur n'autorise pas plus d'un passage; si vous essayez une deuxième passe, vous constaterez qu'elle est vide. Par conséquent, les opérations telles que elem in cont
sont prises en charge par les conteneurs, mais ne peuvent pas être prises en charge par les itérateurs: une fois que vous avez vérifié si un élément est " in " l'itérateur, l'itérateur est détruit!
D'autre part, obtenir un conteneur requiert généralement une copie, telle que la création d'une liste à partir des clés du dictionnaire.
L'objet view
possède le meilleur des deux mondes: il se comporte comme un conteneur et ne copie pas le dictionnaire! En fait, il s’agit d’une sorte de conteneur virtuel en lecture seule qui fonctionne en se liant au dictionnaire sous-jacent. Je ne sais pas si cela se voit ailleurs dans le Python standard.
Modifier:
@AntonyHatchkins: la raison pour laquelle elle ne renvoie pas de fonction de générateur est qu'elle ne permet pas d'opération rapide dans
. Oui, dans
fonctionne pour les fonctions du générateur (lorsque vous les appelez). C'est-à-dire que vous pouvez faire ceci:
def f():
for i in range(10):
yield i
5 in f() # True
Mais selon la définition de dans
, si le côté droit est un générateur, python passera par tous les éléments n
du générateur - conduisant à O (n)
complexité temporelle. Vous ne pouvez rien y faire car c’est le seul comportement significatif d’un générateur arbitraire.
D'autre part, dans le cas de la vue du dictionnaire, vous pouvez implémenter dans
à votre guise, car vous en savez plus sur les données que vous gérez. Et en fait, dans
est mis en œuvre avec la complexité de O (1)
à l'aide d'une table de hachage. Vous pouvez le vérifier en exécutant
>>> d = dict(zip(range(50000000), range(50000000)))
>>> 49999999 in d
True
>>> 49999999 in iter(d) # kinda how generator function would work
True
>>>
et en remarquant à quelle vitesse le premier dans
est comparé au deuxième dans
.
Comme cela a déjà été mentionné dans la question correspondante, view a la méthode len ()
, ce qui manque à l'itérateur (la liste en dispose néanmoins).
Un autre avantage de renvoyer une vue au lieu d’une liste est qu’au moins pour les clés, les tests d’appartenance sont optimisés dans les opérations O (1) au lieu de O (N) pour la liste (ou l’itérateur).