2012-12-03 4 views
4

Existe-t-il un moyen de faire une opération ternaire sur un dict où le test est has_key() sans toucher à l'erreur de clé? à savoirOpération ternaire sur le dictionnaire

variable = dict["the_key"] if dict.has_key("the_key") else "something" 

(cette touche l'erreur touche évidemment)

défaut, ce qui est la façon la plus pythonique d'attribuer un tas de valeurs variables en fonction d'un dict qui peuvent ou peuvent ne pas avoir les clés en question? Répétition:

if dict.has_key('key'): 
    value = dict['key'] 
else: 
    value = "value" 

ad nausée semble être très inélégant.

+1

Vous devez apprendre à consulter la documentation de la bibliothèque python. – Marcin

+1

Votre exemple ne doit pas déclencher KeyError. L'opérateur ternaire n'évalue que l'un des résultats. – BrenBarn

+0

Utilisez '' the_key '' dans d' au lieu de 'd.has_key ('the_key')'. Ce dernier n'existe pas dans Python 3. – argentpepper

Répondre

5

réponse Jochen Ritzel est la bonne façon de le faire 99,9999% du temps:

variable = d.get("the key", "something") 

Comme il fait remarquer, il ne vous permet pas de court-circuiter l'évaluation de la valeur par défaut valeur. En général, vous vous en fichez. La valeur par défaut est "something", certainement pas. Cela n'a d'importance que si la valeur par défaut est dangereuse ou très chère à générer.

Seulement dans ce cas, vous pouvez et devriez utiliser votre idée.Sauf que vous voulez in au lieu de has_key (parce qu'il est plus lisible et plus rapide, et non dépréciée):

variable = d["the key"] if "the key" in d else expensiveComputation() 

Cependant, il est probablement utile d'utiliser une déclaration if au lieu d'une expression ternaire, parce que le fait que vous » re en évitant le expensiveComputation est important, et vous voulez qu'il soit plus visible:

if "the_key" in d: 
    variable = d["the key"] 
else: 
    variable = expensiveComputation() 

Si vous attendez le cas par défaut sont rares, ce qui est mieux:

try: 
    variable = d["the key"] 
except KeyError: 
    variable = expensiveComputation() 

Si pour une raison quelconque, vous devez éviter de regarder la clé deux fois, et vous ne pouvez pas non traiter avec des exceptions, et vous avez besoin de court-circuiter la valeur par défaut, à la fois:

sentinel = object() 
variable = d.get(sentinel) 
if variable == sentinel: 
    variable = expensiveComputation() 

Et oui, vous pouvez envelopper tout cela dans une fonction, donc c'est un one-liner, mais vous ne voulez certainement pas cacher le fait que vous faites trois choses rares à la fois.

Ou, bien sûr, vous pouvez simplement faire faire:

d = collections.defaultdict(expensiveComputation) 

Ensuite, il est juste:

variable = d["the key"] 

Cela a l'effet secondaire de mettre d["the key"]-expensiveComputation() avant de le retourner à vous, donc un appel ultérieur à d["the key"] retournera la même valeur. Si cela semble approprié, c'est la meilleure réponse; Si vous n'utilisez jamais la même clé deux fois, ou si ces choses sont énormes et inutiles, etc., c'est une mauvaise idée.

Ou, alternativement, vous pouvez remplacer la méthode dict.__missing__ au lieu d'utiliser defaultdict:

class MyDict(dict): 
    def __missing__(self, key): 
     return expensiveComputation() 

Puis, encore une fois, il est juste:

variable = d["the key"] 

Celui-ci est approprié lorsque vous souhaitez générer le valeur séparément chaque fois, et ne pas le garder pour plus tard.

+1

Si vous avez besoin de la clé pour faire le calcul coûteux, vous pouvez utiliser une sous-classe 'dict' qui remplace '__missing__' plutôt qu'un' defaultdict'. – kindall

+0

Bon point, @kindall; Je vais mettre à jour la réponse. – abarnert

10

Ce:

mydict.get(key, default_value) 

Non 100% le même que celui default_value est évalué tout de suite alors que la partie else est évaluée uniquement lorsque la condition est remplie.

0
value = 'value' 
if 'key' in dict: 
    value = dict['key'] 

ou définir une valeur par défaut

dict.get ('clé', 'valeur')

1

variable = d['the_key'] if 'the_key' in d else 'something'

+0

C'est la bonne/meilleure réponse pour un certain nombre de raisons: c'est une expression ternaire comme demandé par l'OP; il utilise l'opérateur 'in' au lieu du 'has_key' déprécié; et il n'évalue pas la clause else à moins que la clé n'existe pas dans le dict. – PaulMcG

Questions connexes