Python 字典和默认值
假设Python 字典和默认值,python,dictionary,coding-style,Python,Dictionary,Coding Style,假设connectionDetails是一本Python字典,那么像这样重构代码的最好、最优雅、最“pythonic”的方法是什么 if "host" in connectionDetails: host = connectionDetails["host"] else: host = someDefaultValue 像这样: host = connectionDetails.get('host', someDefaultValue) 对于多个不同的默认值,请尝试以下操作:
connectionDetails
是一本Python字典,那么像这样重构代码的最好、最优雅、最“pythonic”的方法是什么
if "host" in connectionDetails:
host = connectionDetails["host"]
else:
host = someDefaultValue
像这样:
host = connectionDetails.get('host', someDefaultValue)
对于多个不同的默认值,请尝试以下操作:
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
虽然.get()
是一个很好的习惯用法,但它比if/else
慢(如果大部分时间都可以预期字典中存在键,则比try/except
慢):
您也可以使用类似的方法:
您可以传递任何普通函数而不是lambda:
from collections import defaultdict
def a():
return 4
b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"
python字典中有一种方法可以做到这一点:
dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
但是,如果尚未定义keyhost
,则此方法会将connectionDetails['host']
的值设置为someDefaultValue
,这与所问问题不同。(这是一个迟来的答案)
另一种方法是对dict
类进行子类化并实现该方法,如下所示:
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'
连接详细信息=连接详细信息(端口=80)
>>>连接详细信息['host']
“本地主机”
>>>连接详细信息[“端口”]
80
>>>连接详细信息['password']
回溯(最近一次呼叫最后一次):
文件“python”,第1行,在
文件“python”,第6行,缺少__
KeyError:“密码”
测试@Tim Pietzcker对PyPy(5.2.0-alpha0)中Python3.3.5的情况的怀疑,我发现
.get()
和if
/else
两种方法的性能确实相似。实际上,在if/else情况下,如果条件和赋值涉及同一个键,则似乎只有一个查找(与上一种情况相比,其中有两个查找)
可以将lamba函数用作一个线性函数。创建一个新对象
connectionDetails2
,该对象可以像函数一样访问
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
现在使用
connectionDetails2(k)
而不是
connectionDetails[k]
如果
k
在键中,则返回字典值,否则返回“DEFAULT”
注意,第二个参数是一个值,不是键。+1表示可读性,但if/else
要快得多。这可能起作用,也可能不起作用。@Tim,你能提供一个参考,说明为什么如果/else
更快吗?@Tim:我认为使用更高级语言的优点之一是解释器能够“看到”函数内部并对其进行优化,用户不必再进行微优化。这不是JIT编译的目的吗?@nishantjr:Python(至少是最常见的CPython变体)没有JIT编译。PyPy确实可以更快地解决这个问题,但我还没有安装它,因为到目前为止,标准Python的速度一直足够快。一般来说,这在现实生活中不太重要——如果需要进行时间关键型的数字运算,Python可能不是首选语言……我仍然不明白为什么if/then
会更快。这两种情况都需要字典查找,除非调用get()
的速度慢得多,否则还有什么原因导致速度慢?@Jens:函数调用很昂贵。在一个人口稠密的字典中,这应该不是什么大问题,对吗?这意味着,如果实际查找成本很高,那么函数调用将不会有多大影响。它可能只在玩具示例中起作用。@zehelvion:字典查找是O(1)
,与字典大小无关,因此函数调用开销是相关的。如果调用函数的开销会让您决定不使用get,这是很奇怪的。使用您的团队成员最了解的方法。我来这里是为了一些不同于OP问题的问题,而您的解决方案正好解决了它。我会+1它,但遗憾的是它不适合get
或类似的方法。这个答案对我很有用,可以确保添加到字典中的内容包括默认键。我的实现有点太长,无法在StackOverflow答案中描述,所以我在这里写了它。请注意,setdefault()
返回值,因此它也可以工作:host=connectionDetails.setdefault('host',someDefaultValue)
。请注意,如果该键以前不存在,它会将connectionDetails['host']
设置为默认值。这是一个很好的惯用解决方案,但存在一个陷阱。如果connectionDetails随None
一起提供,或将emptyString作为键值对中的一个值提供,则可能会出现意外结果。默认值
字典可能会无意中删除其中一个值。(另请参见)我对您投了赞成票,但您的解决方案的问题是dicts与[]一起工作,而lambdas与()一起工作
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
connectionDetails2(k)
connectionDetails[k]