Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Extraire d'un dictionnaire un sous-dictionnaire

21 réponses
Avatar
Olivier Miakinen
Bonjour,

Je cherche Í  résoudre élégamment un problème. Comme souvent j'ai déjÍ 
une idée de la solution, d'o͹ ma question consistant Í  extraire un
sous-dictionnaire d'un dictionnaire. Mais dans un second temps je vais
exposer le vrai problème au cas o͹ mon idée ne serait pas optimale.

====
Voici donc ma question. Supposons que j'ai un dictionnaire, par exemple
mondict = { "t" : "TRUC", "m" : "MACHIN", "b" : "BIDULE", "c" : "CHOSE" }.

J'ai par ailleurs une liste de clés, keys = ["b", "c", "t", "z"], ou un tuple
keys = ("b", "c", "t", "z"), ou un set keys = {"b", "c", "t", "z"}, selon ce
qui sera le plus simple.

Je voudrais, Í  partir de keys (qu'il soit liste, tuple ou set) et de mon
dictionnaire, obtenir un dictionnaire ne contenant que les entrées présentes
dans keys, dans mon exemple "b", "c" et "t", pas l'entrée "m", sans que cela
ne provoque une erreur Í  cause de "z".

Donc :
resultat = { "t" : "TRUC", "b" : "BIDULE", "c" : "CHOSE" }

====
Et maintenant le vrai problème.

Je voudrais appeler une fonction du type :
def lafonction(b=None, c=None, t=None, z=None):
....
en lui passant les valeurs pour b, c, t et z, si elles existent, se trouvant
dans mon dictionnaire mondict. Du coup un truc du genre :
lafonction(**mondict)
mais sans que cela provoque une erreur Í  cause de l'entrée "m".


Cordialement,
--
Olivier Miakinen

10 réponses

1 2 3
Avatar
Julien Palard
Le 5/25/21 Í  12:13 AM, Olivier Miakinen a écrit :> Comme souvent j'ai
déjÍ > une idée de la solution, d'o͹ ma question consistant Í  extraire
un> sous-dictionnaire d'un dictionnaire.
C'est l'occasion de dégainer un dictionnaire en compréhension :
{key: value for key, value in mondict.items() if key in keys}
Et maintenant le vrai problème.
Je voudrais appeler une fonction du type :
def lafonction(b=None, c=None, t=None, z=None):
....
en lui passant les valeurs pour b, c, t et z, si elles existent, se trouvant
dans mon dictionnaire mondict. Du coup un truc du genre :
lafonction(**mondict)
mais sans que cela provoque une erreur Í  cause de l'entrée "m".

« Explicit is better » me tente de te proposer simplement :
lafonction(mondict.get("b"), mondict.get("c"), mondict.get("t"),
mondict.get("z"))
qui prend du sens aussi dès qu'une des valeur par défaut n'est plus None
mais 0, ou dès qu'un paramètre n'est plus optionnel, ...
Bonne journée,
--
[Julien Palard](https://mdk.fr)
Avatar
Olivier Miakinen
Bonjour,
Le 25/05/2021 08:07, Julien Palard m'a répondu :
Le 5/25/21 Í  12:13 AM, Olivier Miakinen a écrit :> Comme souvent j'ai
déjÍ > une idée de la solution, d'o͹ ma question consistant Í  extraire
un> sous-dictionnaire d'un dictionnaire.
C'est l'occasion de dégainer un dictionnaire en compréhension :
{key: value for key, value in mondict.items() if key in keys}

Tout simplement ! J'avais cru essayer ça mais j'ai dÍ» me planter dans la syntaxe
car ça n'avait pas fonctionné. Cela dit je ne me rappelle pas exactement ce que
j'avais tenté.
DéjÍ  merci pour cette solution.
Et maintenant le vrai problème.
Je voudrais appeler une fonction du type :
def lafonction(b=None, c=None, t=None, z=None):
....
en lui passant les valeurs pour b, c, t et z, si elles existent, se trouvant
dans mon dictionnaire mondict. Du coup un truc du genre :
lafonction(**mondict)
mais sans que cela provoque une erreur Í  cause de l'entrée "m".

« Explicit is better » me tente de te proposer simplement :
lafonction(mondict.get("b"), mondict.get("c"), mondict.get("t"),
mondict.get("z"))
qui prend du sens aussi dès qu'une des valeur par défaut n'est plus None
mais 0, ou dès qu'un paramètre n'est plus optionnel, ...

Sauf que, justement, lorsqu'une valeur par défaut n'est plus None ou qu'un
paramètre est optionnel ça force la valeur None et ça je ne le veux pas.
D'ailleurs je n'avais pas donné un exemple de fonction représentatif mais ce
qui m'intéresse ce sont les classes nntplib.NNTP et nntplib.NNTP_SSL :
<https://docs.python.org/3.8/library/nntplib.html>
class nntplib.NNTP(host, port9, user=None, password=None, readermode=None,
usenetrcͺlse[, timeout])
</>
--
Olivier Miakinen
Avatar
Nicolas
Bonjour,
Quelque chose comme ceci ? :
mondict = {"t" : "TRUC", "m" : "MACHIN", "b" : "BIDULE", "c" : "CHOSE"}
keys = ["b", "c", "t", "z"]
new_dict = {}
for k in keys :
try :
new_dict[k] = mondict[k]
except KeyError :
pass
print (new_dict)
C'est basique mais ça fait le job.
Nicolas
Avatar
Nicolas
Autre version sans try/except :
mondict = {"t" : "TRUC", "m" : "MACHIN", "b" : "BIDULE", "c" : "CHOSE"}
keys = ["b", "c", "t", "z"]
new_dict = {}
for k in keys :
if k in mondict :
new_dict[k] = mondict[k]
print (new_dict)
Si des problèmes de performance se posent, une des deux solutions
peut-être meilleure que l'autre.
Nicolas
Avatar
Olivier Miakinen
Le 25/05/2021 10:58, Nicolas m'a répondu :
Autre version sans try/except :
[...]
Si des problèmes de performance se posent, une des deux solutions
peut-être meilleure que l'autre.

Merci, mais la solution directe donnée par Julien me semble encore
meilleure, non seulement en concision et en lisibilité, mais
probablement aussi en performance (quoique ça ne fasse sans doute
aucune différence dans mon cas).
--
Olivier Miakinen
Avatar
Olivier Miakinen
Le 25/05/2021 10:07, je répondais Í  Julien Palard :
{key: value for key, value in mondict.items() if key in keys}

Tout simplement ! J'avais cru essayer ça mais j'ai dÍ» me planter dans la syntaxe
car ça n'avait pas fonctionné. Cela dit je ne me rappelle pas exactement ce que
j'avais tenté.

Ça y est, je me rappelle mon erreur, j'avais écrit « and » au lieu de « if ».
{key: value for key, value in mondict.items() and key in keys}
=>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'key' is not defined
Eh oui, je ne suis encore que débutant en Python, je n'ai pas les bons réflexes.
--
Olivier Miakinen
Avatar
Nicolas
Le 25/05/2021 Í  11:50, Olivier Miakinen a écrit :
Le 25/05/2021 10:58, Nicolas m'a répondu :
Autre version sans try/except :
[...]
Si des problèmes de performance se posent, une des deux solutions
peut-être meilleure que l'autre.

Merci, mais la solution directe donnée par Julien me semble encore
meilleure, non seulement en concision et en lisibilité, mais
probablement aussi en performance (quoique ça ne fasse sans doute
aucune différence dans mon cas).

Pas de soucis.
Dans la réponse Í  Julien :
"Sauf que, justement, lorsqu'une valeur par défaut n'est plus None ou qu'un
paramètre est optionnel ça force la valeur None et ça je ne le veux pas."
J'ai ai déduit que la solution ne convenait pas.
Mais j'ai mal compris ;)
Nicolas
Avatar
Nicolas
Le 25/05/2021 Í  11:56, Olivier Miakinen a écrit :
Le 25/05/2021 10:07, je répondais Í  Julien Palard :
{key: value for key, value in mondict.items() if key in keys}

Tout simplement ! J'avais cru essayer ça mais j'ai dÍ» me planter dans la syntaxe
car ça n'avait pas fonctionné. Cela dit je ne me rappelle pas exactement ce que
j'avais tenté.

Ça y est, je me rappelle mon erreur, j'avais écrit « and » au lieu de « if ».
{key: value for key, value in mondict.items() and key in keys}
=>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'key' is not defined
Eh oui, je ne suis encore que débutant en Python, je n'ai pas les bons réflexes.

Le dictionnaire en compréhension est moins lisible mais plus concis que
les solutions "éclatées" que j'ai proposées (je sais, certains ne seront
pas d'accord). Et c'est probablement plus rapide aussi.
Avatar
Alain Ketterlin
Olivier Miakinen <om+ writes:
Je cherche Í  résoudre élégamment un problème. Comme souvent j'ai déjÍ 
une idée de la solution, d'o͹ ma question consistant Í  extraire un
sous-dictionnaire d'un dictionnaire.

Je pense que la solution de Julien est imbattable.
Et maintenant le vrai problème.
Je voudrais appeler une fonction du type :
def lafonction(b=None, c=None, t=None, z=None):
....
en lui passant les valeurs pour b, c, t et z, si elles existent, se trouvant
dans mon dictionnaire mondict. Du coup un truc du genre :
lafonction(**mondict)
mais sans que cela provoque une erreur Í  cause de l'entrée "m".

Tu peux aussi ajouter un argument Í  la fonction pour collecter les
déchets :
def lafonction(b=None, c=None, t=None, z=None, **trash):
....
Pas besoin de toucher Í  ton dictionnaire dans ce cas.
-- Alain.
Avatar
Olivier Miakinen
Bonjour,
Le 25/05/2021 11:58, Nicolas m'a répondu:
[...] la solution directe donnée par Julien me semble encore
meilleure, non seulement en concision et en lisibilité, mais
probablement aussi en performance (quoique ça ne fasse sans doute
aucune différence dans mon cas).

Pas de soucis.
Dans la réponse Í  Julien :
"Sauf que, justement, lorsqu'une valeur par défaut n'est plus None ou qu'un
paramètre est optionnel ça force la valeur None et ça je ne le veux pas."

Ça c'est ce que j'ai répondu Í  sa deuxième proposition, celle qui justement
ne créait pas un autre dictionnaire Í  partir du premier.
--
Olivier Miakinen
1 2 3