你可以用Python键切换,而不是Python上的整数吗?

由于OrderedDict具有列表(有序元素)和字典(带键而不是索引)的功能,因此您可以使用键切片是很自然的。

>>> from collections import OrderedDict
>>> cities = OrderedDict((('san francisco', 650), ('new york', 212), ('shanghai', 8621), ('barcelona', 42423)))
>>> test['shanghai':]  # I want all the cities from shanghai to the end of the list
TypeError: unhashable type

这有什么有趣的是,这不是你会看到由于OrderedDictionary .__ getslice__不被执行的错误。我尝试向OrderedDict添加一个我自己的__getslice__方法,但是我继续遇到这个TypeError问题。似乎Python正在做一些类型检查,以强制切片键只是整数,在他们甚至被传递到__getslice__函数之前,如何愚蠢!

>>> class BetterOrderedDict(OrderedDict):
        def __getslice__(self, start=None, end=None, step=1):
            return 'potato'

>>> test = BetterOrderedDict((('one', 1), ('two', 2), ('three', 3), ('four', 4)))
>>> print test[1:4]
'potato'                           # ok this makes sense so far

>>> test['one':'four']
TypeError: unhashable type         # WTF, strings are hashable!

所以我的问题是,为什么我不能实现非int切片,什么样的类型检查是阻止切片键甚至达到我的__getslice__函数,我可以通过在C中实现我的BetterOrderedDict绑定来覆盖它吗?

__getslice__是不推荐使用的切片方式。而应该使用__getitem__处理slice对象:

from collections import OrderedDict

class SlicableDict(OrderedDict):
    def __getitem__(self, key):
        if isinstance(key, slice):
            return 'potato({},{},{})'.format(key.start, key.stop, key.step)
        return super(SlicableDict, self).__getitem__(key)

>>> s = SlicableDict(a=1, b=2, c=3)
>>> s
SlicableDict([('a', 1), ('c', 3), ('b', 2)])
>>> s['a']
1
>>> s['a':'c']
'potato(a,c,None)'

如果你需要的不仅仅是马铃薯,你可以按照以下方式实施所有三个切片操作:

def _key_slice_to_index_slice(items, key_slice):
    try:
        if key_slice.start is None:
            start = None
        else:
            start = next(idx for idx, (key, value) in enumerate(items)
                         if key == key_slice.start)
        if key_slice.stop is None:
            stop = None
        else:
            stop = next(idx for idx, (key, value) in enumerate(items)
                        if key == key_slice.stop)
    except StopIteration:
        raise KeyError
    return slice(start, stop, key_slice.step)

class SlicableDict(OrderedDict):
    def __getitem__(self, key):
        if isinstance(key, slice):
            items = self.items()
            index_slice = _key_slice_to_index_slice(items, key)
            return SlicableDict(items[index_slice])
        return super(SlicableDict, self).__getitem__(key)

    def __setitem__(self, key, value):
        if isinstance(key, slice):
            items = self.items()
            index_slice = _key_slice_to_index_slice(items, key)
            items[index_slice] = value.items()
            self.clear()
            self.update(items)
            return
        return super(SlicableDict, self).__setitem__(key, value)

    def __delitem__(self, key):
        if isinstance(key, slice):
            items = self.items()
            index_slice = _key_slice_to_index_slice(items, key)
            del items[index_slice]
            self.clear()
            self.update(items)
            return
        return super(SlicableDict, self).__delitem__(key)
http://stackoverflow.com/questions/27912308/how-can-you-slice-with-string-keys-instead-of-integers-on-a-python-ordereddict

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:你可以用Python键切换,而不是Python上的整数吗?