python字典和默认值

假设connectionDetails是一个Python字典,那么重构代码的最好,最优雅,最“pythonic”的方式是这样的:

 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慢, 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 

python字典中有一个方法可以做到这一点: dict.setdefault

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

但是,如果关键host尚未定义,则此方法将connectionDetails['host']的值设置为someDefaultValue ,而不像所问的问题。

(这是一个迟到的答案)

另一种方法是__missing__() 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' 

testing@Tim Pietzcker对Python 3.3.5的PyPy(5.2.0-alpha0)中的情况的怀疑,我发现的确如此.get()if / else方法都是相似的。 实际上,if / else情况下,如果条件和赋值包含相同的键(与最后一次查找的情况相比),则甚至只有一次查找。

 >>>> 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函数作为单线程。 创build一个新的对象connectionDetails2 ,它像一个函数一样被访问…

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

现在使用

 connectionDetails2(k) 

代替

 connectionDetails[k] 

如果k在键中,则返回字典值,否则返回"DEFAULT"