Ajouter à un dict uniquement si une condition est remplie
J'utilise urllib.urlencode
pour construire des paramètres web POST, cependant il y a quelques valeurs que je veux seulement ajouter si une valeur autre que None
existe pour eux.
Apple = 'green'
orange = 'orange'
params = urllib.urlencode({
'Apple': Apple,
'orange': orange
})
Cela fonctionne très bien, mais si je rends la variable orange
facultative, comment puis-je l'empêcher d'être ajoutée aux paramètres? Quelque chose comme ça (pseudocode):
Apple = 'green'
orange = None
params = urllib.urlencode({
'Apple': Apple,
if orange: 'orange': orange
})
J'espère que c'était assez clair, quelqu'un sait-il comment résoudre ce problème?
Vous devrez ajouter la clé séparément, après avoir créé le dict
initial:
params = {'Apple': Apple}
if orange is not None:
params['orange'] = orange
params = urllib.urlencode(params)
Python n'a pas de syntaxe pour définir une clé comme conditionnelle; vous pouvez utiliser une compréhension dict si vous aviez déjà tout dans une séquence:
params = urllib.urlencode({k: v for k, v in (('orange', orange), ('Apple', Apple)) if v is not None})
mais ce n'est pas très lisible.
Pour utiliser la réponse de sqreept, voici une sous-classe de dict
qui se comporte comme vous le souhaitez:
class DictNoNone(dict):
def __setitem__(self, key, value):
if key in self or value is not None:
dict.__setitem__(self, key, value)
d = DictNoNone()
d["foo"] = None
assert "foo" not in d
Cela permettra aux valeurs des clés existantes d'être modifiées à None
, mais assigner None
à une clé qui n'existe pas est un no-op. Si vous vouliez définir un élément sur None
sur supprimer dans le dictionnaire s'il existe déjà, vous pouvez le faire:
def __setitem__(self, key, value):
if value is None:
if key in self:
del self[key]
else:
dict.__setitem__(self, key, value)
Les valeurs de None
can entrent si vous les passez pendant la construction. Si vous voulez éviter cela, ajoutez un __init__
méthode pour les filtrer:
def __init__(self, iterable=(), **kwargs):
for k, v in iterable:
if v is not None: self[k] = v
for k, v in kwargs.iteritems():
if v is not None: self[k] = v
Vous pouvez également le rendre générique en l'écrivant afin de pouvoir passer la condition souhaitée lors de la création du dictionnaire:
class DictConditional(dict):
def __init__(self, cond=lambda x: x is not None):
self.cond = cond
def __setitem__(self, key, value):
if key in self or self.cond(value):
dict.__setitem__(self, key, value)
d = DictConditional(lambda x: x != 0)
d["foo"] = 0 # should not create key
assert "foo" not in d
Assez vieille question mais voici une alternative utilisant le fait que la mise à jour d'un dict avec un dict vide ne fait rien.
def urlencode_func(Apple, orange=None):
kwargs = locals().items()
params = dict()
for key, value in kwargs:
params.update({} if value is None else {key: value})
return urllib.urlencode(params)
params = urllib.urlencode({
'Apple': Apple,
**({'orange': orange} if orange else {}),
})
Vous pouvez effacer Aucun après l'affectation:
Apple = 'green'
orange = None
dictparams = {
'Apple': Apple,
'orange': orange
}
for k in dictparams.keys():
if not dictparams[k]:
del dictparams[k]
params = urllib.urlencode(dictparams)
J'ai fait ça. J'espère que cette aide.
Apple = 23
orange = 10
a = {
'Apple' : Apple,
'orange' if orange else None : orange if orange else None
}
Production attendue : {'orange': 10, 'Apple': 23}
Bien que, si orange = None
, il y aura alors une seule entrée pour None:None
. Par exemple, considérez ceci:
Apple = 23
orange = None
a = {
'Apple' : Apple,
'orange' if orange else None : orange if orange else None
}
Production attendue : {None: None, 'Apple': 23}
Une autre réponse valable est que vous pouvez créer votre propre conteneur de type dict qui ne stocke pas de valeurs None.
class MyDict:
def __init__(self):
self.container = {}
def __getitem__(self, key):
return self.container[key]
def __setitem__(self, key, value):
if value != None:
self.container[key] = value
def __repr__(self):
return self.container.__repr__()
a = MyDict()
a['orange'] = 'orange';
a['lemon'] = None
print a
rendements:
{'orange': 'orange'}
J'aime vraiment l'astuce soignée dans la réponse ici: https://stackoverflow.com/a/50311983/3124256
Mais, il y a quelques pièges:
- Dupliquer les tests
if
(répétés pour la clé et la valeur) - Pesky
None: None
entrée dans ledict
résultant
Pour éviter cela, vous pouvez procéder comme suit:
Apple = 23
orange = None
banana = None
a = {
'Apple' if Apple else None: Apple,
'orange' if orange else None : orange,
'banana' if banana else None: banana,
None: None,
}
del a[None]
Production attendue : {'Apple': 23}
Noter la None: None
l'entrée garantit deux choses:
- La touche
None
sera toujours présente (del
ne générera pas d'erreur) - Le contenu de 'Aucune valeur' n'existera jamais dans le dict (au cas où vous oublieriez de
del
après)
Si vous n'êtes pas inquiet à propos de ces choses, vous pouvez le laisser de côté et envelopper le del dans un try...except
(ou vérifiez si la touche None
est présente avant del
ing). Pour adresser le numéro 2 alternativement, vous pouvez également mettre la vérification conditionnelle sur la valeur (en plus de la clé).
fruits = [("Apple", get_Apple()), ("orange", get_orange()), ...]
params = urllib.urlencode({ fruit: val for fruit, val in fruits if val is not None })