J'ai une interview récemment. L'intervieweur m'a demandé comment itérer dict dans python
. J'ai dit que tous les moyens utilisent pour statement. Mais il m'a dit que diriez-vous de lambda ?
Je me sens très mal à l'aise et je considère lambda comme une fonction d'anonymat, mais comment itérer un dict? un code comme celui-ci:
new_dict = sorted(old_dict.items(), lambda x: x[1]) # sorted by value in dict
Mais dans ce code, le lambda est utilisé en tant que fonction pour fournir la clé comparée. Que pensez-vous de cette question?
Vous ne parcourez pas avec lambda
. Il existe différentes manières d'itérer un objet itérable en Python:
for
(votre réponse)[x for x in y]
, le dictionnaire {key: value for key, value in x}
et l'ensemble {x for x in y}
(x for x in y)
map
, all
, itertools
) next
jusqu'à ce que StopIteration
se produise.Remarque: 3 ne l'itère pas à moins que vous n'itériez plus tard sur ce générateur. Dans le cas de 4 cela dépend de la fonction.
Pour itérer des collections spécifiques telles que dict ou list, il peut y avoir plus de techniques telles que while col: remove element
ou avec des astuces de découpage d'index.
Maintenant lambda
entre en scène. Vous pouvez utiliser lambdas dans certaines de ces fonctions, par exemple: map(lambda x: x*2, [1, 2, 3])
. Mais lambda ici n’a rien à voir avec le processus d’itération lui-même, vous pouvez passer une fonction régulière map(func, [1, 2, 3])
.
Vous pouvez itérer dict en utilisant lambda comme ceci:
d = {'a': 1, 'b': 2}
values = map(lambda key: d[key], d.keys())
Utiliser une simple lambda
pour tout répéter en Python semble très faux. La méthode la plus utilisée par Pythonic pour itérer des séquences et des collections consiste à utiliser des interprétations de liste et des expressions génératrices telles que @Andrey.
Si l'intervieweur s'appuyait sur les réponses plus théoriques/informatiques, il est intéressant de noter que l'utilisation de lambdas pour itérer est tout à fait possible , même si je dois souligner que cela n'est ni utile ni pythonique dans d'autres contextes que des exercices académiques:
# the legendary Y Combinator makes it possible
# to let nameless functions recurse using an indirection
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
# our iterator lambda
it = lambda f: lambda Lst: (Lst[0], f(Lst[1:])) if Lst else None
# see it in action:
Y(it)([1,2,3])
=> (1, (2, (3, None)))
lambda
lui-même n'itère rien. Comme vous le pensiez, cela définit simplement une fonction anonyme - mis à part la règle syntaxique selon laquelle il est uniquement possible de pouvoir avoir une expression, une variable lambda
ne fait rien de plus qu'une fonction similaire créée à l'aide de def
. Le code à l'intérieur de lambda peut itérer quelque chose, mais de la même manière que n'importe quelle autre fonction pourrait utiliser (à condition qu'il s'agisse d'expressions et qu'elles sont donc valides dans une lambda
).
Dans l'exemple que vous mentionnez en utilisant sorted
, la fonction de clé est appelée sur chaque élément de la liste en cours de tri, mais c'est sorted
lui-même qui le fait et qui effectue l'itération. Lorsque vous fournissez une fonction clé, sorted
fait quelque chose de similaire à ceci:
def sorted(seq, key):
decorated = [(key(elem), i) for i, elem in enumerate(seq)]
# Sort using the normal Tuple lexicographic comparisons
decorated.sort()
return [seq[i] for _,i in decorated]
Comme vous pouvez le constater, sorted
effectue l'itération ici, pas la lambda
. En effet, il n'y a aucune raison pour que la clé a soit un lambda - aucune fonction (ni aucun appelable) ne fera autant que sorted
est concerné.
Au niveau le plus bas, il n’existe en réalité qu’un moyen d’itérer un dict (ou, en fait, tout autre itérable) en Python, qui consiste à utiliser le protocole itérateur. C'est ce que la boucle for
fait en coulisse, et vous pouvez également utiliser une instruction while
comme celle-ci:
it = iter(my_iterable)
while True:
try:
val = next(it)
except StopIteration:
# Run else clause of for loop
break
else:
# Run for loop body
Les commentaires qui y sont contenus ne font pas strictement partie du protocole itérateur, ils font plutôt partie de la boucle for
(mais le fait d'avoir au moins un corps de boucle constitue principalement le point d'itérer en premier lieu).
D'autres fonctions et syntaxes qui consomment des itérables (telles que des compréhensions de liste, de set et de dict, des expressions de générateur ou des commandes intégrées telles que sum
, sorted
ou max
) utilisent toutes ce protocole, soit:
for
,while
ci-dessus (surtout pour les modules écrits en C),Une classe peut être faite pour que ses instances deviennent itérables de deux manières:
__iter__
(appelée par iter
), qui renvoie un itérateur. Cet itérateur a une méthode appelée __next__
(juste next
en Python 2) appelée par next
et renvoie la valeur à l'emplacement actuel de l'itérateur et la fait avancer (ou soulève StopIteration
si elle est déjà à la fin); ou__getitem__
de telle sorte que l'exécution de my_sequence[0]
, my_sequence[1]
, jusqu'à my_sequence[n-1]
(où n
est le nombre d'éléments de la séquence), et que les index supérieurs génèrent une erreur. En général, vous souhaitez également définir __len__
, qui est utilisé lorsque vous effectuez len(my_sequence)
.Le meilleur moyen d'itérer dict en python est:
dic ={}
iter_dic = dic.iteritems().next
iter_dic()
...
iter_dic()
Mais vous pouvez le construire avec lambda func:
iter_dic = lambda dic: dic.keys()[0],dic.pop(dic.keys()[0])
iter_dic(dic)
...
iter_dic(dic)