使用list获取列表的Python dict索引,与Perl哈希一样

jco*_*ctx 6 python perl hash dictionary

Perl有一个构造(如Joe Z所指出的那样称为"哈希切片"),用于索引到带有列表的哈希以获取列表,例如:

%bleah = (1 => 'a', 2 => 'b', 3 => 'c');
print join(' ', @bleah{1, 3}), "\n";
Run Code Online (Sandbox Code Playgroud)

执行给出:

a c
Run Code Online (Sandbox Code Playgroud)

我知道在Python中处理这个问题的最简单,最易读的方法是列表理解:

>>> bleah = {1: 'a', 2: 'b', 3: 'c'}
>>> print ' '.join([bleah[n] for n in [1, 3]])
a c
Run Code Online (Sandbox Code Playgroud)

因为:

>>> bleah[[1, 2]]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Run Code Online (Sandbox Code Playgroud)

我还有其他一些更好的方法吗?也许在Python3中,我还没有做过多少工作?如果没有,是否有人知道是否已经为此提交了PEP?我的google-fu无法找到一个.

"它不是Pythonic":是的,我知道,但我希望它能成为现实.它简洁和可读性,因为它永远不会是Python的索引到与unhashable类型的字典,其在指数中的异常处理程序迭代为你而不是barfing不会打破目前大多数代码.

注意:正如评论中指出的那样,这个测试用例可以重写为一个列表,完全避免使用dict,但我正在寻找一个通用的解决方案.

the*_*eye 5

我能想到的最好的方法是使用itemgetter

from operator import itemgetter
bleah = {1: 'a', 2: 'b', 3: 'c'}
getitems = itemgetter(1, 3)
print getitems(bleah)
Run Code Online (Sandbox Code Playgroud)

因此,如果您想传递索引列表,那么您可以解压缩参数,如下所示(感谢 @koffein 指出这一点:))

getitems = itemgetter(*[1, 3])
Run Code Online (Sandbox Code Playgroud)

然后你可以join喜欢这个

print ' '.join(getitems(bleah))
Run Code Online (Sandbox Code Playgroud)

或者简单地

print ' '.join(itemgetter(1, 3)(bleah))
Run Code Online (Sandbox Code Playgroud)


jco*_*ctx 1

目前,我在评论中采纳 Hyperboreus 的建议并重写__getitem__,但我仍然认为将其作为默认的字典行为是有意义的:

\n\n
jcomeau@aspire:~$ cat /tmp/sliceable.py; echo ---; python /tmp/sliceable.py\n'SliceableDict test'\nimport sys, os\nclass SliceableDict(dict):\n\xc2\xa0def __init__(self, d = {}):\n\xc2\xa0 super(SliceableDict, self).__init__(d)\n\xc2\xa0def __getitem__(self, index):\n\xc2\xa0 try:\n\xc2\xa0 \xc2\xa0return super(SliceableDict, self).__getitem__(index)\n\xc2\xa0 except TypeError:\n\xc2\xa0 \xc2\xa0return [super(SliceableDict, self).__getitem__(x) for x in index]\n\xc2\xa0def __setitem__(self, index, value):\n\xc2\xa0 try:\n\xc2\xa0 \xc2\xa0super(SliceableDict, self).__setitem__(index, value)\n\xc2\xa0 except:\n\xc2\xa0 \xc2\xa0for i in range(len(index)):\n\xc2\xa0 \xc2\xa0 super(SliceableDict, self).__setitem__(index[i], value[i])\nd = SliceableDict({1: 'a', 2: 'b', 3: 'c'})\nprint d[2]\nprint d[[1, 3]]\nd[[1, 3]] = ['x', 'y']\nprint d\n---\nb\n['a', 'c']\n{1: 'x', 2: 'b', 3: 'y'}\n
Run Code Online (Sandbox Code Playgroud)\n\n

(根据上面 tobyink 的评论修改为添加左值功能 -- jc 2013-12-12)

\n