Словари и значения по умолчанию

Предполагая, что connectionDetails – это словарь Python, какой лучший, самый элегантный, самый «питонический» способ рефакторинга кода?

 if "host" in connectionDetails: host = connectionDetails["host"] else: host = someDefaultValue 

Как это:

 host = connectionDetails.get('host','someDefault') 

Вы также можете использовать defaultdict следующим образом:

 from collections import defaultdict a = defaultdict(lambda: "default", key="some_value") a["blabla"] => "default" a["key"] => "some_value" 

Вы можете передать любую обычную функцию вместо lambda:

 from collections import defaultdict def a(): return 4 b = defaultdict(a, key="some_value") b['absent'] => 4 b['key'] => "some_value" 

В то время как .get() – хорошая идиома, она медленнее, чем if/else (и медленнее, чем try/except того, что большую часть времени можно ожидать от присутствия ключа в словаре):

 >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", ... stmt="try:\na=d[1]\nexcept KeyError:\na=10") 0.07691968797894333 >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", ... stmt="try:\na=d[2]\nexcept KeyError:\na=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:\na=d[1]\nelse:\na=10") 0.10071221458065338 >>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", ... stmt="if 2 in d:\na=d[2]\nelse:\na=10") 0.06966537335119938 

Для нескольких разных значений по умолчанию попробуйте следующее:

 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 по 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 

Для этого в словарях python существует метод: dict.setdefault

 connectionDetails.setdefault('host',someDefaultValue) host = connectionDetails['host'] 

Однако этот метод устанавливает значение connectionDetails['host'] в someDefaultValue если основной host еще не определен, в отличие от заданного вопроса.

(это поздний ответ)

Альтернативой является подclass classа 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  File "python", line 6, in __missing__ KeyError: 'password' 

Тестирование подозрительности @Tim Pietzcker о ситуации в PyPy (5.2.0-alpha0) для Python 3.3.5, я нахожу, что и то, и другое .get() и if / else аналогичные. На самом деле кажется, что в случае if / else существует только один поиск, если условие и назначение include один и тот же ключ (сравните с последним случаем, когда есть два поиска).

 >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", .... stmt="try:\na=d[1]\nexcept KeyError:\na=10") 0.011889292989508249 >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", .... stmt="try:\na=d[2]\nexcept KeyError:\na=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:\na=d[1]\nelse:\na=10") 0.011475925013655797 >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", .... stmt="if 2 in d:\na=d[2]\nelse:\na=10") 0.009605801998986863 >>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}", .... stmt="if 2 in d:\na=d[2]\nelse:\na=d[1]") 0.017342638995614834 

Вы можете использовать функцию lamba для этого как однострочный. Создайте новый объект connectionDetails2 которому обращаются как функция …

 connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT" 

Теперь используйте

 connectionDetails2(k) 

вместо

 connectionDetails[k] 

который возвращает значение словаря, если k находится в ключах, в противном случае он возвращает "DEFAULT"

  • IDictionary в .NET 4 не ковариант
  • Значение словаря C #, очищающего, когда я очищаю список, ранее назначенный ему ... почему?
  • Словарь, возвращающий значение по умолчанию, если ключ не существует
  • Использование поля объекта в качестве общего ключа словаря
  • Определение, если словарь Swift содержит ключ и получает какие-либо его значения
  • Сортировка std :: map с использованием значения
  • Как конвертировать JSON в HashMap с помощью Gson?
  • Серийный class, содержащий член словаря
  • Регулярное выражение, которое никогда не будет соответствовать чему-либо
  • Swagger: карта
  • Pandas groupby.size vs series.value_counts vs collections.Counter с несколькими сериями
  • Давайте будем гением компьютера.