1
votes

Comment ajouter des propriétés à une liste de dictionnaires via une compréhension de liste en python3?

J'ai une liste de dictionnaires. Pour chaque dict, je dois transmettre l'une de ses propriétés à une fonction, puis attribuer une nouvelle propriété en fonction du résultat de cette fonction.

Par exemple: J'ai une liste de pages d'un site. Je dois les parcourir et, en fonction de l'URL, attribuer le nom de l'auteur à une propriété dans le dict.

pages = [??? for page in pages]

Cela fonctionne. Mais est encombré et ne semble pas pythonique. pages [index] ressemble à une chose que je ne devrais pas avoir à faire en Python.

Y a-t-il un moyen de le faire via une compréhension de liste? Ou une autre manière plus pythonique?

for index, page in enumerate(pages):
    pages[index]['author'] = get_author(page['url'])


2 commentaires

Une compréhension de liste construit une liste à partir d'une liste existante. Dans votre cas, vous souhaitez mettre à jour les éléments de liste existants. Une compréhension de liste est inappropriée pour ce travail.


@DYZ a du sens. Y a-t-il une alternative ici?


3 Réponses :


1
votes

Une compréhension de liste construit une liste à partir d'une liste existante. Dans votre cas, vous souhaitez mettre à jour les éléments de liste existants. Une compréhension de liste est inappropriée pour ce travail.

Votre solution peut cependant être quelque peu améliorée:

for page in pages:
    page['author'] = get_author(page['url'])


4 commentaires

Je pouvais me tromper, mais j'avais cru comprendre que la modification directe de page ne propagerait pas ce changement aux pages . Je vais vérifier


@snazzybouche ouais, vous avez tort. list est modifiable et page sera une référence à l'objet existant dans pages , pas une copie ou quelque chose comme ça. Cela marche.


@snazzybouche Vous pensez probablement à réassigner au nom de la variable; quelque chose comme page = ... . Dans ce cas, vous modifiez l'objet pointé par page en place, donc ça ira.


@gmds Oui, on dirait que c'est là que je me suis mêlé. J'allais dire que j'ai utilisé enumerate beaucoup plus que je n'aurais dû, mais si c'est le cas, je ne me suis pas trop mal débrouillé.



2
votes

Vous pouvez utiliser une telle liste compréhension:

[{'url': 1, 'author': 'hello'}, {'url': 2, 'author': 'bye'}]

Cela crée un nouveau dict pour chaque dict code> avec une clé supplémentaire, author , basée sur la valeur de get_author appliquée à la valeur correspondant à la clé url . p >

Notez qu'il ne modifie pas la list d'origine .

Exemple:

def get_author(i):
    if i == 1:
        return 'hello'

    else:
        return 'bye'

pages = [{'url': 1},
         {'url': 2}]

result = [{**page, **{'author': get_author(page['url'])}} for page in pages]
print(result)
Sortie:

result = [{**page, 'author': get_author(page['url'])} 
          for page in pages]

# This works too:

result = [dict(**page, author=get_author(page['url'])) 
          for page in pages]

# but is less preferred because it will fail for input containing non-string keys


0 commentaires

0
votes

Je peux voir deux solutions "pythoniques":

  • Création d'un nouveau dict à partir de la page décompressée et de la nouvelle valeur "author":
pages = [p.update(author=get_author(p['url'])) or  p for p in pages]
  • Une petite astuce en utilisant l'opérateur 'or':
pages = [{**p, 'author': get_author(p['url'])} for p in pages]

Puisque p.update () renvoie None, None ou p sera toujours la version mise à jour de p.

Le premier semble être plus lisible mais je pense que le second bat le premier en performance.


0 commentaires