J'essaye de faire:
award_dict = {
"url" : "http://facebook.com",
"imageurl" : "http://farm4.static.flickr.com/3431/3939267074_feb9eb19b1_o.png",
"count" : 1,
}
def award(name, count, points, desc_string, my_size, parent) :
if my_size > count :
a = {
"name" : name,
"description" : desc_string % count,
"points" : points,
"parent_award" : parent,
}
a.update(award_dict)
return self.add_award(a, siteAlias, alias).award
Mais si je me sentais vraiment encombrant dans la fonction, et j'aurais préféré le faire:
return self.add_award({
"name" : name,
"description" : desc_string % count,
"points" : points,
"parent_award" : parent,
}.update(award_dict), siteAlias, alias).award
Pourquoi la mise à jour ne renvoie-t-elle pas l'objet pour que vous puissiez enchaîner?
JQuery fait cela pour faire du chaînage. Pourquoi n'est-ce pas acceptable en python?
python
dictionary
language-design
language-features
Paul Tarjan
la source
la source
newdict = dict(dict001, **dict002)
Réponses:
Python implémente principalement une saveur pragmatiquement teintée de séparation commande-requête : les mutateurs retournent
None
(avec des exceptions induites de manière pragmatique telles quepop
;-) donc ils ne peuvent pas être confondus avec les accesseurs (et dans le même esprit, l'affectation n'est pas une expression, l'instruction -expression la séparation est là, et ainsi de suite).Cela ne veut pas dire qu'il n'y a pas beaucoup de façons de fusionner les choses quand vous le voulez vraiment, par exemple, faire
dict(a, **award_dict)
un nouveau dict un peu comme celui que vous semblez souhaiter.update
retourner - alors pourquoi ne pas utiliser CELA si vous sentez vraiment que c'est important ?Edit : au fait, pas besoin, dans votre cas particulier, de créer en
a
cours de route, non plus:crée un dict unique avec exactement la même sémantique que le vôtre
a.update(award_dict)
(y compris, en cas de conflit, le fait que les entréesaward_dict
écrasent celles que vous donnez explicitement; pour obtenir l'autre sémantique, c'est-à-dire avoir des entrées explicites "gagnantes" de tels conflits, passeraward_dict
comme seul argument de position , avant les mots-clés, et dépourvu de la**
forme -dict(award_dict, name=name
etc etc).la source
a
complètement, btw,TypeError
dict(old_dict, old_key=new_value)
ne lancera pas plusieurs valeurs pour le mot-clé et ne retournera pas de nouveau dict.L'API de Python, par convention, fait la distinction entre les procédures et les fonctions. Les fonctions calculent de nouvelles valeurs à partir de leurs paramètres (y compris tout objet cible); les procédures modifient les objets et ne renvoient rien (c'est-à-dire qu'elles renvoient None). Les procédures ont donc des effets secondaires, les fonctions n'en ont pas. update est une procédure, donc elle ne renvoie pas de valeur.
La motivation pour le faire de cette façon est que sinon, vous pourriez avoir des effets secondaires indésirables. Considérer
Si reverse (qui inverse la liste sur place) renvoie également la liste, les utilisateurs peuvent penser que reverse renvoie une nouvelle liste qui est assignée à bar, et ne remarque jamais que foo est également modifiée. En rendant le retour inverse Aucun, ils reconnaissent immédiatement que la barre n'est pas le résultat du renversement, et regarderont de plus près quel est l'effet du retour.
la source
reverse(foo)
est bizarre.bar=foo[:]
), puis de rétablir la copie.bar = foo.reverse()
, vous pourriez penser que cefoo
n'est pas modifié. Pour éviter toute confusion, vous avez à la foisfoo.reverse()
etbar = reversed(foo)
.C'est simple car:
la source
Notez qu'en plus de renvoyer le dict fusionné, il modifie le premier paramètre sur place. Donc dict_merge (a, b) modifiera a.
Ou, bien sûr, vous pouvez tout faire en ligne:
la source
lambda
ne doit pas être utilisé comme ça, au lieu d' utiliser la fonction classique à ladef
placea.update(b) or a
pas assez de réputation pour le commentaire laissé sur la première réponse
@beardc cela ne semble pas être une chose CPython. PyPy me donne "TypeError: les mots clés doivent être des chaînes"
La solution
**kwargs
ne fonctionne que car le dictionnaire à fusionner ne contient que des clés de type string .c'est à dire
contre
la source
Ce n'est pas que ce n'est pas acceptable, mais cela
dicts
n'a pas été mis en œuvre de cette façon.Si vous regardez l'ORM de Django, il utilise largement le chaînage. Ce n'est pas découragé, vous pouvez même hériter
dict
et ne remplacer queupdate
pour faire la mise à jour etreturn self
, si vous le voulez vraiment.la source
aussi proche que possible de votre solution proposée
la source
Pour ceux qui arrivent en retard à la fête, j'avais mis un peu de temps ensemble (Py 3.7), montrant que les
.update()
méthodes basées semblent un peu (~ 5%) plus rapides lorsque les entrées sont conservées et sensiblement (~ 30%) plus rapides lors de la mise à jour sur place. .Comme d'habitude, tous les repères doivent être pris avec un grain de sel.
Les délais pour les opérations sur place sont un peu plus délicats, il faudrait donc le modifier le long d'une opération de copie supplémentaire (le premier timing est juste pour référence):
la source
la source
Je viens d'essayer cela moi-même dans Python 3.4 (je n'ai donc pas pu utiliser la
{**dict_1, **dict_2}
syntaxe sophistiquée ).Je voulais pouvoir avoir des clés sans chaîne dans les dictionnaires et fournir une quantité arbitraire de dictionnaires.
De plus, je voulais créer un nouveau dictionnaire, alors j'ai choisi de ne pas l'utiliser
collections.ChainMap
(un peu la raison pour laquelle je ne voulais pas utiliser audict.update
départ.Voici ce que j'ai fini par écrire:
la source