Python 仅当尚未设置值时,才在dict中设置值
如果尚未设置值,那么在Python 仅当尚未设置值时,才在dict中设置值,python,dictionary,lazy-evaluation,Python,Dictionary,Lazy Evaluation,如果尚未设置值,那么在dict中设置值的最具python风格的方法是什么 目前,我的代码使用if语句: if "timeout" not in connection_settings: connection_settings["timeout"] = compute_default_timeout(connection_settings) dict.get(key,default)适用于使用dict的代码,而不适用于准备将dict传递给另一个函数的代码。你可以用它来设置一些东西,但在我
dict
中设置值的最具python风格的方法是什么
目前,我的代码使用if语句:
if "timeout" not in connection_settings:
connection_settings["timeout"] = compute_default_timeout(connection_settings)
dict.get(key,default)
适用于使用dict的代码,而不适用于准备将dict传递给另一个函数的代码。你可以用它来设置一些东西,但在我看来,它并不漂亮:
connection_settings["timeout"] = connection_settings.get("timeout", \
compute_default_timeout(connection_settings))
即使dict包含密钥,也会评估计算函数;臭虫 Defaultdict是指默认值相同时 当然,有很多次您将不需要计算的primative值设置为默认值,它们当然可以使用
dict.setdefault
。但更复杂的情况如何?一种方法是:
if key not in dict:
dict[key] = value
这是一个有点不确定的答案,但我想说,最具python风格的是if语句。您抵制了使用
\uuuu setitem\uuuu
或其他方法对其进行线性化的冲动。您已经避免了逻辑中可能出现的错误,因为在尝试巧妙地进行短路和
/或
攻击时,可能会出现现有但错误的值。很明显,compute函数在没有必要的时候没有被使用
它清晰、简洁、易读——像蟒蛇一样 将精确地“仅当尚未设置值时才在dict中设置值”
您仍然需要计算值以将其作为参数传入:
connection_settings.setdefault("timeout", compute_default_timeout(connection_settings))
我使用以下命令将kwargs修改为非默认值并传递给另一个函数:
def f( **non_default_kwargs ):
kwargs = {
'a':1,
'b':2,
}
kwargs.update( non_default_kwargs )
f2( **kwargs )
这具有以下优点:
- 你不必键入两次键
- 所有这些都是在一个函数中完成的
- 您可能需要
dict.setdefault
:
创建新词典并设置一个值:
>>> d = {}
>>> d.setdefault('timeout', 120)
120
>>> d
{'timeout': 120}
如果已设置值,dict.setdefault
不会覆盖该值:
>>> d['port']=8080
>>> d.setdefault('port', 8888)
8080
>>> d
{'port': 8080, 'timeout': 120}
我发现,利用dict
.get()
方法的返回是None
(Falsy),再加上或
,在密钥不存在的情况下推迟对昂贵的网络请求的评估,既方便又明显
d = dict()
def fetch_and_set(d, key):
d[key] = ("expensive operation to fetch key")
if not d[key]:
raise Exception("could not get value")
return d[key]
...
value = d.get(key) or fetch_and_set(d, key)
具体地说,在我的例子中,我正在从缓存构建一个新的字典,然后在加速
fn()
调用之后更新缓存
下面是我使用的简化视图
j = load(database) # dict
d = dict()
# see if desired keys are in the cache, else fetch
for key in keys:
d[key] = j.get(key) or fetch(key, network_token)
fn(d) # use d for something useful
j.update(d) # update database with new values (if any)
由于Python3.9可以使用合并操作符
|
合并两个词典。以右边的格言为准:
d={key:value}|d
注意:这将创建一个具有更新值的新字典。“即使dict包含键,也会评估计算函数;bug”这不是bug:
在调用dict.get()
之前必须调用计算默认超时()
——这可能不是OP想要的,但这是正确的行为。引用自问题,因此很明显,该行为等同于OP已经考虑的某个bug(我自己不会称之为bug,但在这种情况下它仍然是不必要和不受欢迎的)。我的观点是,它显然对OP没有用处,因为他们已经因为这个原因放弃了一个同等的替代方案。。顺便说一句,我曾经问过一个关于这种行为的问题,是否可以让它变得“懒惰”…)我认为您对用例的假设太多了。OP可能没有(甚至不想要)一个预先存在和预先计算的合理默认值集合。如上所述,这样做是正确的。@98:但是,这并不能使dict.setdefault()
成为正确的选择,因为它不是唯一的dict.setdefault()
有。这与原始问题中显示的有什么不同吗?对未来的谷歌用户来说:这可能不是提问者想要的答案,但这是你想要的答案。@coredump错误我不同意。使用if key not in dict:dict[k]=value
(如问题和接受的答案中所建议)更具可读性。dict.setdefault()
设计用于在有效获取密钥值时,始终确保密钥存在。将其用作setter只会与正常使用背道而驰。如果关键字不在dictionary:dictionary[key]=compute\u default\u timeout(:…)
中,则使用将更加清晰和直接。此外,OP特别要求提供一个直到需要时才计算新值的选项,这是您无法使用dict.setdefault()
@MartijnPieters实现的,coredumperror已经提到这不是OP想要的答案。否则,避免重复查找(计算哈希等)是一个很好的解决方案。@Alexey:查找属性和调用方法也会有代价。由于字符串的散列值是缓存的,对于setdefault()
您总是必须首先生成默认值,如果“超时”不在连接设置中,我会把钱放在上:连接设置['timeout']=compute\u default\u timeout(连接设置)
获胜。但现在我们正在进行微优化,这将取决于关键点未命中率和命中率。我同意,现在使用python没有更好的方法,但我认为它有明显的缺点。特别是,您正在重复密钥的名称,因此拼写错误产生的bug已经成熟。因为它是一个字符串,所以如果在if语句中输入“timeout”,而在赋值中输入“timout”,大多数linter将无法捕获它。我在很大程度上不喜欢Ruby,但有一件事我很怀念| |=操作符。”连接设置[“timeout”]| |=计算_值()”简洁易读。顺便说一句,| |=远非完美。Ruby中该运算符的陷阱是如果值在字典中,但为falsy(0,空字符串等)