web-dev-qa-db-fra.com

lambda en python peut itérer dict?

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?

6
chyoo CHENG

Vous ne parcourez pas avec lambda. Il existe différentes manières d'itérer un objet itérable en Python:

  1. déclaration for (votre réponse)
  2. Compréhension, y compris la liste [x for x in y], le dictionnaire {key: value for key, value in x} et l'ensemble {x for x in y}
  3. Expression du générateur: (x for x in y)
  4. Passer à la fonction qui va le parcourir (module map, all, itertools
  5. Appelez manuellement la fonction 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]).

7
Andrey

Vous pouvez itérer dict en utilisant lambda comme ceci:

d = {'a': 1, 'b': 2}
values = map(lambda key: d[key], d.keys())
3
Eugene Soldatov

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)))
1
souser12345

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:

  • En utilisant une boucle Python for,
  • Faire quelque chose comme la boucle while ci-dessus (surtout pour les modules écrits en C),
  • Déléguer à une autre fonction ou un autre élément de syntaxe utilisant l'une de ces fonctions

Une classe peut être faite pour que ses instances deviennent itérables de deux manières:

  • Fournissez le protocole d'itérateur directement. Vous avez besoin d'une méthode appelée __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
  • Implémente une partie du protocole de séquence (ce qui signifie se comporter comme une liste ou un tuple). Pour une itération en aval, il suffit de définir __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).
0
lvc

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)
0
G.S