Ответы:
Как это:
host = connectionDetails.get('host', someDefaultValue)
if/elseнамного быстрее. Это может или не может играть роль.
if/elseбыстрее?
Вы также можете использовать defaultdictтак:
from collections import defaultdict
a = defaultdict(lambda: "default", key="some_value")
a["blabla"] => "default"
a["key"] => "some_value"
Вы можете передать любую обычную функцию вместо лямбды:
from collections import defaultdict
def a():
return 4
b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"
getни в подобные методы.
Хотя .get()это хорошая идиома, она медленнее, чем if/else(и медленнее, чем try/exceptесли бы большую часть времени можно было ожидать присутствия ключа в словаре):
>>> 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 будет быстрее. В обоих случаях требуется поиск по словарю, и если вызов get()не так много медленнее, чем остальные счета для замедления?
O(1)в словаре не зависит от размера словаря, поэтому издержки вызова функции актуальны.
Для нескольких различных значений по умолчанию попробуйте это:
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указано значение empty или строка в качестве одного из значений в парах ключ-значение. В defaultsсловаре может быть непреднамеренно пропущено одно из его значений. (см. также stackoverflow.com/questions/6354436 )
В словарях python есть метод для этого: dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
Однако этот метод устанавливает значение connectionDetails['host']для someDefaultValueесли ключ hostеще не задан, в отличие от того, что задан вопрос.
setdefault()возвращает значение, так что это работает , а также: host = connectionDetails.setdefault('host', someDefaultValue). Просто помните, что он установит connectionDetails['host']значение по умолчанию, если ключ не был там раньше.
(это поздний ответ)
Альтернативой является создание подкласса dictкласса и реализация __missing__()метода следующим образом:
class ConnectionDetails(dict):
def __missing__(self, key):
if key == 'host':
return "localhost"
raise KeyError(key)
Примеры:
>>> 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'
Проверяя подозрение @Tim Pietzcker'а о ситуации в PyPy (5.2.0-alpha0) для Python 3.3.5, я обнаружил, что действительно оба .get()и if/ elseway работают одинаково. На самом деле кажется, что в случае if / else есть даже только один поиск, если условие и присваивание включают один и тот же ключ (сравните с последним случаем, когда есть два поиска).
>>>> 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
Вы можете использовать функцию lamba для этого в качестве однострочника. Создайте новый объект, connectionDetails2доступ к которому осуществляется как функция ...
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
Сейчас использую
connectionDetails2(k)
вместо того
connectionDetails[k]
который возвращает значение словаря, если kнаходится в ключах, в противном случае он возвращает"DEFAULT"