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"