Ответы:
Как это:
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
/ else
way работают одинаково. На самом деле кажется, что в случае 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"