Python 还有比dict.get(<;thing>;、dict.get(<;other>;)更好的吗?
在Python中Python 还有比dict.get(<;thing>;、dict.get(<;other>;)更好的吗?,python,dictionary,Python,Dictionary,在Python中 >>> x = {'spam': 'a lot'} >>> x.get('eggs', x.get('spam')) 'a lot' 但是,.get()组合似乎有些尴尬 有没有更好的方法可以说,“这可能是两个键中的一个,我不在乎哪个键,只要给我值就行了”我想我会这样做,因为它可能更具可读性: >>> x = {'spam': 'a lot'} >>> results = x.get('eggs') or
>>> x = {'spam': 'a lot'}
>>> x.get('eggs', x.get('spam'))
'a lot'
但是,.get()
组合似乎有些尴尬
有没有更好的方法可以说,“这可能是两个键中的一个,我不在乎哪个键,只要给我值就行了”我想我会这样做,因为它可能更具可读性:
>>> x = {'spam': 'a lot'}
>>> results = x.get('eggs') or x.get('spam')
>>> results
'a lot'
您的代码看起来实际上效率更高,但它必须同时评估这两个函数,因此使用或进行简化实际上效果更好
这可能不是您想要的,如果x['eggs']返回空值,请注意该行为(但您确实说过您不介意获取任何一个值):
意外情况可能是这样的:
>>> results = '' or None
>>> print(results)
None
使用映射
和过滤器
:
>>> x = {'spam': 'a lot'}
>>> filter(None, map(x.get, ('eggs', 'spam'))) # [0]
['a lot']
具有列表理解能力:
>>> [x.get(k) for k in ('eggs', 'spam') if k in x]
['a lot']
在需要检查两个以上的键时非常有用:
>>> filter(None, map(x.get, ('eggs', 'foo', 'bar', 'spam')))
['a lot']
我能想出的最“正确”的解决方案也是最丑陋的。那太糟糕了。我的两个标准是:
- 避免出现
0或None
角情况
- 如果存在一把钥匙,则短路
尽管它很丑陋,但这实际上是最快的执行:
x['eggs'] if 'eggs' in x else x.get('spam')
timeit
结果:
>>> op = lambda: x.get('eggs', x.get('spam'))
>>> aaron = lambda: x.get('eggs') or x.get('spam')
>>> ndpu = lambda: filter(None, map(x.get, ['eggs', 'spam']))[0]
>>> mhlester = lambda: x['eggs'] if 'eggs' in x else x.get('spam')
>>>
>>> timeit(op, number=100000)
0.04057041245972073
>>> timeit(aaron, number=100000)
0.04477326960257777
>>> timeit(ndpu, number=100000)
0.13210876799140614
>>> timeit(mhlester, number=100000)
0.03425499248118058
如果你只是在寻找一个单一的班轮,我相信已经发布的三元涵盖了它:
result = myDict['eggs'] if 'eggs' in myDict else myDict.get('spam')
如果您只是在寻找可读的答案,我想您只需要使用If
语句
result = myDict.get('eggs', 'fail')
if result == 'fail':
result = myDict.get('spam')
像这样分手有什么不好的地方吗?我喜欢Stick的答案,但如果你要做两次以上的事情(遵循“三个法则”),我会把它放在一个类中。
另外:速度不应该是首要考虑的问题——除非确实需要。追求简单易读
class MyDict(dict):
def get(self, first_key, second_key, default=None):
if first_key in self:
return self[first_key]
elif second_key in self:
return self[second_key]
else:
return default
x = MyDict({"spam":"a lot"})
print x.get("eggs","spam")
# "a lot"
但是如果x['eggs']
是0
,该怎么办?我想要0
,而不是None
至于效率,你的效率实际上更高,因为它会短路。函数在调用之前需要计算所有参数,因此get
s都保证在您的函数中被调用。@mhlester:或者更糟的是,您可能会得到“很多”
!没错,对于x['eggs']=0,它可能会产生意想不到的结果,我会记下来。正如@mhlester所说,它实际上更快,而且更容易阅读。我建议改为使用defaultdict。这种模式有奇怪的副作用,我自己也从未想过要使用这种模式。@davidermann:defaultdict
如何用于此?OP的版本带来了什么奇怪的副作用?@JohnY这感觉像是一种默认模式(虽然可能不是),因此是默认模式。副作用是,改变x[“垃圾邮件”]
会改变get的行为。@davidermann:嗯,OP真正想做的是(1)尝试“鸡蛋”,如果这不起作用,尝试“垃圾邮件”,如果不起作用,则获得None
;或者(2)获取“鸡蛋”或“垃圾邮件”,不管是哪一个,如果两者都失败,则获取None
。对于defaultdict
您将使用哪个工厂函数来获取这些行为?如果您不介意将d['spam']
的值写入d['eggs']
除了返回它之外,您还可以执行类似d=defaultdict(partial(d.get,'spam'))的操作。
…嗯?这有什么帮助?为什么您要“注释”第一个示例中的[0]
,而不在第二个示例中包含它?除了这些问题之外,我确实认为这个答案很有用,以防有许多可能的键需要检查。为了完整性,还值得注意的是,这可以通过列表理解而不是map
,filter
@JohnY空列表得到结果,所以我认为最好不要使用[0]
使用此方法实现多功能性。。。如果
需要,我明白你关于空箱子的观点;但是如果没有索引,您可能会得到多个结果。最后,我想你确实需要做更多的检查来真正获得正确的功能。除了你的版本是唯一一个可以引发异常的版本。编辑。它比以前的get
花费的时间长了50%,但对于简洁来说,它仍然是最快的+1。但速度不应该是决定因素,除非需要达成一致。我最喜欢的仍然是OP,尽管有更高的开销,不需要myDict.get('eggs')
,因为如果您在代码的该部分,'eggs'
已经确认在myDict
中。这个答案与mhlester的答案类似,只是你还建议使用更长的形式,如果myDict['egs']
实际上等于'fail'
,那么这是不正确的。而且,是
不是字符串相等性的正确测试。两个很长的字符串可以相等(使用==
),但不能相同(使用是
)。哦,是的,这很公平。我已经习惯了“我的值不是零”,所以我反过来应用了相同的值。哇。但希望大家能理解,“失败”值在理想情况下永远不会是“鸡蛋”的值——在这种情况下,人们不会使用鸡蛋式的值作为哨兵。我本打算驳回这个答案,但重新阅读OP的问题,我注意到他实际上并没有要求最短或最快的解决方案,只是一个“更好”的解决方案。如果反复使用,这肯定会更好。你甚至可以通过结合地图/过滤器或列表理解(如ndpu的答案)将其扩展到任意数量的键来检查。我一直在玩(一个变体)这个答案,我真的很喜欢它。根据OP的任务,这可能有点过分,但实现起来很容易。
class MyDict(dict):
def get(self, first_key, second_key, default=None):
if first_key in self:
return self[first_key]
elif second_key in self:
return self[second_key]
else:
return default
x = MyDict({"spam":"a lot"})
print x.get("eggs","spam")
# "a lot"