可以将 dict.get() 嵌套在另一个内部,还是这种糟糕的设计?
Is it okay to nest a dict.get() inside another or is this bad design?
因此,我正在处理一个代码库,其中字典包含一些关键信息。在开发过程中的某个时刻,其中一个键的名称发生了变化,但旧键在很多地方仍然存在。让我们调用键 new
和 old
以供参考。
为了兼容旧版本,我正在做这样的事情:
dict_name.get(new_key,dict_name.get(old_key,None))
这个设计不好还是没问题? Why/Why 不是吗?
说明示例:(基于@Alexander 的输入)
有两个词典d1和d2。
d1={k1:v1,old_key:some_value}
d2={k1:v1,new_key:some_value}
我现在正在设计的函数可以像字典一样获取 d1 或 d2 作为参数。我的函数应该能够获取 some_value,无论是否存在 old_key 或 new_key。
dict.get
正是出于这个原因,因此如果键不在其中,您可以使用默认值。
有双重后备非常好。例如:
d = {}
result = d.get('new_key',d.get('old_key', None))
这意味着 result
在最坏的情况下是 None
,但没有错误(这首先是 get
的目标。
换句话说,它会优先获得new_key
的值,old_key
是第二优先,None
是第三。
还值得注意的是 get(key, None)
与 get(key)
相同,因此您可能希望缩短该行:
result = d.get('new_key', d.get('old_key'))
如果你想避免多次调用 get
(例如,如果你必须调用其中的 2 个以上,它将不可读)你可以这样做:
priority = ('new_key', 'old_key', 'older_key', 'oldest_key')
for key in priority:
result = d.get(key)
if result is not None:
break
并且 result
成为该循环中首先遇到的任何内容,或者 None
否则
这是一个合理的方法。唯一的缺点是它会对两个键执行get
,这在大多数情况下不会影响性能。
我唯一的笔记是挑剔的:
dict
为保留字,请勿作为变量使用
None
是默认的,所以可以去掉old_key
,例如:
info.get('a', info.get('b'))
回应"Is there a way to prevent the double call?":是的,存在几种合理的方法=)。
单行线可能看起来像:
info['a'] if 'a' in info else info.get('b')
如果你的键更长,它开始变得难以阅读。
更详细的方法是将其扩展为完整的语句:
val = None
if 'a' in info:
val = info['a']
elif 'b' in info:
val = info['b']
最后一个通用选项(*keys
之后的默认选项)将仅适用于 python 3):
def multiget(info, *keys, default=None):
''' Try multiple keys in order, or default if not present '''
for k in keys:
if k in info:
return info[k]
return default
这将让您干净地解决多个调用,例如:
option_1 = multiget(info, 'a', 'b')
option_2 = multiget(info, 'x', 'y', 'z', default=10)
如果这在某种程度上是多个 api 版本的流行病或某种东西(?)你甚至可以包装 dict
,尽管它可能有点矫枉过正:
>>> class MultiGetDict(dict):
... def multiget(self, *keys, default=None):
... for k in keys:
... if k in self:
... return self[k]
... return default
...
>>> d = MultiGetDict({1: 2})
>>> d.multiget(1)
2
>>> d.multiget(0, 1)
2
>>> d.multiget(0, 2)
>>> d.multiget(0, 2, default=3)
3
根据提供的示例词典,我认为这是糟糕的设计...
假设您的原始词典是:
d1 = {'k1': 1, 'k2': 2}
如果我没理解错的话,你就'update'其中一个键,例如:
d1 = {'k3': 1, 'k2': 2}
如果您尝试通过以下方式访问:
d1.get('k3', d1.get('k1')) # 'k3' is new key, 'k1' is old key.
那么第一个查找将始终存在,第二个查找将永远不会被使用。
如果您的意思是新词典看起来像:
d2 = {'k1': 1, 'k2': 2, 'k3': 1}
那么您将 'same' 数据存储在字典中的两个不同位置,这肯定会导致麻烦(类似于数据库中的规范化数据)。例如,如果 'k3' 的值更新为 3
,那么 k1
的值也需要更新。
鉴于您的示例中提供的词典:
d1={k1: v1, old_key: some_value}
d2={k1: v1, new_key: some_value}
我假设 some_value
在两者中都是相等的,即 d1[old_key] == d2[new_key]
。如果是这样,那么您 可以 使用 d2.get(new_key, d1.get(old_key)
。然而,它看起来就像一团糟。
- 如果
some_value
需要更新,例如,必须在两个词典中更新。
- 您存储
some_value
两次是在浪费内存。
- 您在
d2
中的 new_key
可能会意外破坏 d1
中的现有密钥。
我建议首先不要更改键名。
因此,我正在处理一个代码库,其中字典包含一些关键信息。在开发过程中的某个时刻,其中一个键的名称发生了变化,但旧键在很多地方仍然存在。让我们调用键 new
和 old
以供参考。
为了兼容旧版本,我正在做这样的事情:
dict_name.get(new_key,dict_name.get(old_key,None))
这个设计不好还是没问题? Why/Why 不是吗?
说明示例:(基于@Alexander 的输入)
有两个词典d1和d2。
d1={k1:v1,old_key:some_value}
d2={k1:v1,new_key:some_value}
我现在正在设计的函数可以像字典一样获取 d1 或 d2 作为参数。我的函数应该能够获取 some_value,无论是否存在 old_key 或 new_key。
dict.get
正是出于这个原因,因此如果键不在其中,您可以使用默认值。
有双重后备非常好。例如:
d = {}
result = d.get('new_key',d.get('old_key', None))
这意味着 result
在最坏的情况下是 None
,但没有错误(这首先是 get
的目标。
换句话说,它会优先获得new_key
的值,old_key
是第二优先,None
是第三。
还值得注意的是 get(key, None)
与 get(key)
相同,因此您可能希望缩短该行:
result = d.get('new_key', d.get('old_key'))
如果你想避免多次调用 get
(例如,如果你必须调用其中的 2 个以上,它将不可读)你可以这样做:
priority = ('new_key', 'old_key', 'older_key', 'oldest_key')
for key in priority:
result = d.get(key)
if result is not None:
break
并且 result
成为该循环中首先遇到的任何内容,或者 None
否则
这是一个合理的方法。唯一的缺点是它会对两个键执行get
,这在大多数情况下不会影响性能。
我唯一的笔记是挑剔的:
dict
为保留字,请勿作为变量使用None
是默认的,所以可以去掉old_key
,例如:
info.get('a', info.get('b'))
回应"Is there a way to prevent the double call?":是的,存在几种合理的方法=)。
单行线可能看起来像:
info['a'] if 'a' in info else info.get('b')
如果你的键更长,它开始变得难以阅读。
更详细的方法是将其扩展为完整的语句:
val = None if 'a' in info: val = info['a'] elif 'b' in info: val = info['b']
最后一个通用选项(
*keys
之后的默认选项)将仅适用于 python 3):def multiget(info, *keys, default=None): ''' Try multiple keys in order, or default if not present ''' for k in keys: if k in info: return info[k] return default
这将让您干净地解决多个调用,例如:
option_1 = multiget(info, 'a', 'b') option_2 = multiget(info, 'x', 'y', 'z', default=10)
如果这在某种程度上是多个 api 版本的流行病或某种东西(?)你甚至可以包装 dict
,尽管它可能有点矫枉过正:
>>> class MultiGetDict(dict):
... def multiget(self, *keys, default=None):
... for k in keys:
... if k in self:
... return self[k]
... return default
...
>>> d = MultiGetDict({1: 2})
>>> d.multiget(1)
2
>>> d.multiget(0, 1)
2
>>> d.multiget(0, 2)
>>> d.multiget(0, 2, default=3)
3
根据提供的示例词典,我认为这是糟糕的设计...
假设您的原始词典是:
d1 = {'k1': 1, 'k2': 2}
如果我没理解错的话,你就'update'其中一个键,例如:
d1 = {'k3': 1, 'k2': 2}
如果您尝试通过以下方式访问:
d1.get('k3', d1.get('k1')) # 'k3' is new key, 'k1' is old key.
那么第一个查找将始终存在,第二个查找将永远不会被使用。
如果您的意思是新词典看起来像:
d2 = {'k1': 1, 'k2': 2, 'k3': 1}
那么您将 'same' 数据存储在字典中的两个不同位置,这肯定会导致麻烦(类似于数据库中的规范化数据)。例如,如果 'k3' 的值更新为 3
,那么 k1
的值也需要更新。
鉴于您的示例中提供的词典:
d1={k1: v1, old_key: some_value}
d2={k1: v1, new_key: some_value}
我假设 some_value
在两者中都是相等的,即 d1[old_key] == d2[new_key]
。如果是这样,那么您 可以 使用 d2.get(new_key, d1.get(old_key)
。然而,它看起来就像一团糟。
- 如果
some_value
需要更新,例如,必须在两个词典中更新。 - 您存储
some_value
两次是在浪费内存。 - 您在
d2
中的new_key
可能会意外破坏d1
中的现有密钥。
我建议首先不要更改键名。