Antworten:
So was:
host = connectionDetails.get('host', someDefaultValue)
if/else
viel schneller. Das könnte eine Rolle spielen oder auch nicht.
if/else
schneller ist?
Sie können auch Folgendes verwenden defaultdict
:
from collections import defaultdict
a = defaultdict(lambda: "default", key="some_value")
a["blabla"] => "default"
a["key"] => "some_value"
Sie können jede gewöhnliche Funktion anstelle von Lambda übergeben:
from collections import defaultdict
def a():
return 4
b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"
get
oder ähnlichen Methoden.
Es .get()
ist zwar eine nette Redewendung, aber langsamer als if/else
(und langsamer als try/except
wenn das Vorhandensein des Schlüssels im Wörterbuch die meiste Zeit erwartet werden kann):
>>> 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
es schneller gehen würde. Beide Fälle erfordern eine Wörterbuch - Lookup, und es sei denn , der Aufruf get()
ist so viel langsamer, was sonst Konten für die Verlangsamung?
O(1)
unabhängig von der Wörterbuchgröße, daher ist der Overhead des Funktionsaufrufs relevant.
Versuchen Sie für mehrere verschiedene Standardeinstellungen Folgendes:
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
oder dem emptyString als einem der Werte in den Schlüssel-Wert-Paaren geliefert wird. Im defaults
Wörterbuch kann möglicherweise einer seiner Werte unbeabsichtigt ausgeblendet werden. (siehe auch stackoverflow.com/questions/6354436 )
In Python-Wörterbüchern gibt es eine Methode, um dies zu tun: dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
Diese Methode setzt jedoch den Wert auf connectionDetails['host']
, someDefaultValue
wenn der Schlüssel host
nicht bereits definiert ist, anders als in der gestellten Frage.
setdefault()
der Wert zurückgegeben wird, sodass dies auch funktioniert : host = connectionDetails.setdefault('host', someDefaultValue)
. Beachten Sie nur, dass connectionDetails['host']
der Standardwert festgelegt wird, wenn der Schlüssel zuvor nicht vorhanden war.
(Dies ist eine späte Antwort)
Eine Alternative besteht darin, die dict
Klasse in Unterklassen zu unterteilen und die __missing__()
Methode wie folgt zu implementieren :
class ConnectionDetails(dict):
def __missing__(self, key):
if key == 'host':
return "localhost"
raise KeyError(key)
Beispiele:
>>> 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'
Wenn ich @Tim Pietzckers Verdacht auf die Situation in PyPy (5.2.0-alpha0) für Python 3.3.5 teste, stelle ich fest, dass tatsächlich beide .get()
und die if
/ else
way eine ähnliche Leistung erbringen . Tatsächlich scheint es im if / else-Fall nur eine einzige Suche zu geben, wenn die Bedingung und die Zuweisung denselben Schlüssel beinhalten (vergleiche mit dem letzten Fall, in dem es zwei Suchen gibt).
>>>> 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
Sie können hierfür eine Lamba-Funktion als Einzeiler verwenden. Erstellen Sie ein neues Objekt, auf connectionDetails2
das wie eine Funktion zugegriffen wird ...
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
Jetzt benutzen
connectionDetails2(k)
anstatt
connectionDetails[k]
Dies gibt den Wörterbuchwert zurück, wenn er k
in den Schlüsseln enthalten ist, andernfalls wird er zurückgegeben"DEFAULT"