J'ai une question sur les idiomes et la lisibilité, et il semble y avoir un choc des philosophies Python pour ce cas particulier:
Je veux construire le dictionnaire A à partir du dictionnaire B. Si une clé spécifique n'existe pas dans B, ne rien faire et continuer.
Quelle est la meilleure façon?
try:
A["blah"] = B["blah"]
except KeyError:
pass
ou
if "blah" in B:
A["blah"] = B["blah"]
"Faire et demander pardon" vs "simplicité et explicitation".
Quel est le meilleur et pourquoi?
python
idioms
readability
defaultdict
code-readability
LeeMobile
la source
la source
if "blah" in B.keys()
, ouif B.has_key("blah")
.A.update(B)
fonctionne pas pour vous?has_key
a été déprécié en faveur dein
et la vérificationB.keys()
change une opération O (1) en une opération O (n)..has_key
est obsolète etkeys
crée une liste inutile dans py2k, et est redondant dans py3kA = dict((k, v) for (k, v) in B if we_want_to_include(k))
.Réponses:
Les exceptions ne sont pas conditionnelles.
La version conditionnelle est plus claire. C'est naturel: il s'agit d'un contrôle de flux simple, pour lequel les conditions sont conçues, pas d'exceptions.
La version d'exception est principalement utilisée comme optimisation lors de ces recherches dans une boucle: pour certains algorithmes, elle permet d'éliminer les tests des boucles internes. Cela n'a pas cet avantage ici. Il a le petit avantage d'éviter d'avoir à dire
"blah"
deux fois, mais si vous en faites beaucoup, vous devriez probablement avoir unemove_key
fonction d' assistance de toute façon.En général, je vous recommande fortement de vous en tenir à la version conditionnelle par défaut, sauf si vous avez une raison spécifique de ne pas le faire. Les conditions sont le moyen évident de le faire, ce qui est généralement une forte recommandation de préférer une solution à une autre.
la source
"blah"
plus souvent, ce qui conduit à une situation plus sujette aux erreurs.Il existe également un troisième moyen qui évite à la fois les exceptions et la double recherche, ce qui peut être important si la recherche est coûteuse:
Dans le cas où vous vous attendez à ce que le dictionnaire contienne des
None
valeurs, vous pouvez utiliser des constantes plus ésotériques commeNotImplemented
,Ellipsis
ou en créer une nouvelle:Quoi qu'il en soit, l'utilisation
update()
est l'option la plus lisible pour moi:la source
D'après ce que j'ai compris, vous souhaitez mettre à jour le dict A avec des paires clé et valeur de dict B
update
est un meilleur choix.Exemple:
la source
A.update({k: v for k, v in B.iteritems() if k in specificset})
Citation directe du wiki de performance Python:
Il semble donc que les deux options soient viables selon la situation. Pour plus de détails, vous pouvez consulter ce lien: Try-except-performance
la source
Je pense que la règle générale ici est d'
A["blah"]
exister normalement, si c'est le cas, essayez-sauf est bon sinon utilisezif "blah" in b:
Je pense que "essayer" est bon marché dans le temps mais "sauf" est plus cher.
la source
Je pense que le deuxième exemple est ce que vous devriez choisir à moins que ce code n'ait du sens:
Gardez à l'esprit que le code sera abandonné dès qu'il y aura une clé qui n'y est pas
B
. Si ce code a du sens, vous devez utiliser la méthode d'exception, sinon utilisez la méthode de test. À mon avis, parce qu'elle est plus courte et exprime clairement l'intention, elle est beaucoup plus facile à lire que la méthode d'exception.Bien sûr, les personnes qui vous disent d'utiliser
update
ont raison. Si vous utilisez une version de Python qui prend en charge la compréhension du dictionnaire, je préférerais fortement ce code:la source
for key in ["foo", "bar", "baz"]: try: A[key] = B[key]
La règle dans les autres langues est de réserver des exceptions pour des conditions exceptionnelles, c'est-à-dire des erreurs qui ne se produisent pas en utilisation régulière. Je ne sais pas comment cette règle s'applique à Python, car StopIteration ne devrait pas exister par cette règle.
la source
Personnellement, je penche vers la deuxième méthode (mais en utilisant
has_key
):De cette façon, chaque opération d'affectation ne comporte que deux lignes (au lieu de 4 avec try / except), et toutes les exceptions levées seront de vraies erreurs ou des choses que vous avez manquées (au lieu d'essayer simplement d'accéder à des clés qui ne sont pas là) .
En fin de compte (voir les commentaires sur votre question),
has_key
est obsolète - donc je suppose que c'est mieux écrit commela source
En commençant
Python 3.8
, et en introduisant les expressions d'affectation (PEP 572) (:=
opérateur), nous pouvons capturer la valeur de la conditiondictB.get('hello', None)
dans une variablevalue
afin à la fois de vérifier si ce n'est pas le casNone
(commedict.get('hello', None)
renvoie soit la valeur associée ouNone
) et de l'utiliser ensuite dans le corps de la condition:la source
Bien que l'accent mis sur le principe "regardez avant de sauter" puisse s'appliquer à la plupart des langages, une approche plus pythonique pourrait être la première approche, basée sur les principes de python. Sans oublier qu'il s'agit d'un style de codage légitime en python. La chose importante est de vous assurer que vous utilisez le bloc try except dans le bon contexte et que vous suivez les meilleures pratiques. Par exemple. faire trop de choses dans un bloc try, attraper une exception très large, ou pire - la clause d'exception nue, etc.
Voir la référence de la documentation python ici .
En outre, ce blog de Brett, l'un des principaux développeurs, aborde la plupart de cela en bref.
Voir une autre discussion SO ici :
la source