Réponses:
Comme ça:
host = connectionDetails.get('host', someDefaultValue)
if/else
est beaucoup plus rapide. Cela pourrait ou non jouer un rôle.
if/else
est plus rapide?
Vous pouvez également utiliser des éléments defaultdict
similaires:
from collections import defaultdict
a = defaultdict(lambda: "default", key="some_value")
a["blabla"] => "default"
a["key"] => "some_value"
Vous pouvez passer n'importe quelle fonction ordinaire au lieu de lambda:
from collections import defaultdict
def a():
return 4
b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"
get
des méthodes similaires.
Bien que ce .get()
soit un bel idiome, il est plus lent que if/else
(et plus lent que try/except
si la présence de la clé dans le dictionnaire peut être attendue la plupart du temps):
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.07691968797894333
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.4583777282275605
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="a=d.get(1, 10)")
0.17784020746671558
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="a=d.get(2, 10)")
0.17952161730158878
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.10071221458065338
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.06966537335119938
if/then
serait plus rapide. Les deux cas ont besoin d' une recherche dans le dictionnaire, et à moins que l'invocation de get()
est donc beaucoup plus lent, ce qui compte le reste du ralentissement?
O(1)
indépendamment de la taille du dictionnaire, donc la surcharge d'appel de fonction est pertinente.
Pour plusieurs valeurs par défaut différentes, essayez ceci:
connectionDetails = { "host": "www.example.com" }
defaults = { "host": "127.0.0.1", "port": 8080 }
completeDetails = {}
completeDetails.update(defaults)
completeDetails.update(connectionDetails)
completeDetails["host"] # ==> "www.example.com"
completeDetails["port"] # ==> 8080
None
ou la emptyString comme l'une des valeurs des paires clé-valeur. Le defaults
dictionnaire pourrait potentiellement avoir une de ses valeurs supprimée involontairement. (voir aussi stackoverflow.com/questions/6354436 )
Il existe une méthode dans les dictionnaires python pour ce faire: dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
Cependant , cette méthode permet de définir la valeur connectionDetails['host']
à someDefaultValue
si la clé host
est pas déjà défini, contrairement à ce que la question posée.
setdefault()
valeur de retour, donc cela fonctionne aussi bien: host = connectionDetails.setdefault('host', someDefaultValue)
. Gardez juste à l'esprit qu'il sera réglé connectionDetails['host']
sur la valeur par défaut si la clé n'était pas là auparavant.
(c'est une réponse tardive)
Une alternative consiste à sous- dict
classer la classe et à implémenter la __missing__()
méthode, comme ceci:
class ConnectionDetails(dict):
def __missing__(self, key):
if key == 'host':
return "localhost"
raise KeyError(key)
Exemples:
>>> connection_details = ConnectionDetails(port=80)
>>> connection_details['host']
'localhost'
>>> connection_details['port']
80
>>> connection_details['password']
Traceback (most recent call last):
File "python", line 1, in <module>
File "python", line 6, in __missing__
KeyError: 'password'
En testant les soupçons de @Tim Pietzcker sur la situation dans PyPy (5.2.0-alpha0) pour Python 3.3.5, je trouve qu'en effet les deux .get()
et le if
/ else
way fonctionnent de manière similaire. En fait, il semble que dans le cas if / else, il n'y a même qu'une seule recherche si la condition et l'affectation impliquent la même clé (comparer avec le dernier cas où il y a deux recherches).
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.011889292989508249
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.07310474599944428
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(1, 10)")
0.010391917996457778
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(2, 10)")
0.009348208011942916
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.011475925013655797
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.009605801998986863
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=d[1]")
0.017342638995614834
Vous pouvez utiliser une fonction lamba pour cela comme une ligne. Créez un nouvel objet connectionDetails2
accessible comme une fonction ...
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
Maintenant, utilisez
connectionDetails2(k)
au lieu de
connectionDetails[k]
qui retourne la valeur du dictionnaire si k
est dans les clés, sinon il retourne"DEFAULT"